From: khartlage Date: Fri, 17 Jan 2003 21:00:10 +0000 (+0000) Subject: first scanner /parser copied from the jdt java version X-Git-Url: http://secure.phpeclipse.com first scanner /parser copied from the jdt java version --- diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/AbstractSyntaxTreeVisitorAdapter.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/AbstractSyntaxTreeVisitorAdapter.java new file mode 100644 index 0000000..2803c97 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/AbstractSyntaxTreeVisitorAdapter.java @@ -0,0 +1,495 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler; + +import net.sourceforge.phpdt.core.compiler.*; +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +/** + * An adapter class for interating through the parse tree. + */ + +public class AbstractSyntaxTreeVisitorAdapter implements IAbstractSyntaxTreeVisitor { + + public void acceptProblem(IProblem problem) {} + public void endVisit( + AllocationExpression allocationExpression, + BlockScope scope) { + } + public void endVisit(AND_AND_Expression and_and_Expression, BlockScope scope) { + } + public void endVisit( + AnonymousLocalTypeDeclaration anonymousTypeDeclaration, + BlockScope scope) { + } + public void endVisit(Argument argument, BlockScope scope) { + } + public void endVisit( + ArrayAllocationExpression arrayAllocationExpression, + BlockScope scope) { + } + public void endVisit(ArrayInitializer arrayInitializer, BlockScope scope) { + } + public void endVisit( + ArrayQualifiedTypeReference arrayQualifiedTypeReference, + BlockScope scope) { + } + public void endVisit( + ArrayQualifiedTypeReference arrayQualifiedTypeReference, + ClassScope scope) { + } + public void endVisit(ArrayReference arrayReference, BlockScope scope) { + } + public void endVisit(ArrayTypeReference arrayTypeReference, BlockScope scope) { + } + public void endVisit(ArrayTypeReference arrayTypeReference, ClassScope scope) { + } + public void endVisit(Assignment assignment, BlockScope scope) { + } + public void endVisit(AssertStatement assertStatement, BlockScope scope) { + } + public void endVisit(BinaryExpression binaryExpression, BlockScope scope) { + } + public void endVisit(Block block, BlockScope scope) { + } + public void endVisit(Break breakStatement, BlockScope scope) { + } + public void endVisit(Case caseStatement, BlockScope scope) { + } + public void endVisit(CastExpression castExpression, BlockScope scope) { + } + public void endVisit(CharLiteral charLiteral, BlockScope scope) { + } + public void endVisit(ClassLiteralAccess classLiteral, BlockScope scope) { + } + public void endVisit(Clinit clinit, ClassScope scope) { + } + public void endVisit( + CompilationUnitDeclaration compilationUnitDeclaration, + CompilationUnitScope scope) { + } + public void endVisit(CompoundAssignment compoundAssignment, BlockScope scope) { + } + public void endVisit( + ConditionalExpression conditionalExpression, + BlockScope scope) { + } + public void endVisit( + ConstructorDeclaration constructorDeclaration, + ClassScope scope) { + } + public void endVisit(Continue continueStatement, BlockScope scope) { + } + public void endVisit(DefaultCase defaultCaseStatement, BlockScope scope) { + } + public void endVisit(DoStatement doStatement, BlockScope scope) { + } + public void endVisit(DoubleLiteral doubleLiteral, BlockScope scope) { + } + public void endVisit(EqualExpression equalExpression, BlockScope scope) { + } + public void endVisit( + ExplicitConstructorCall explicitConstructor, + BlockScope scope) { + } + public void endVisit( + ExtendedStringLiteral extendedStringLiteral, + BlockScope scope) { + } + public void endVisit(FalseLiteral falseLiteral, BlockScope scope) { + } + public void endVisit(FieldDeclaration fieldDeclaration, MethodScope scope) { + } + public void endVisit(FieldReference fieldReference, BlockScope scope) { + } + public void endVisit(FloatLiteral floatLiteral, BlockScope scope) { + } + public void endVisit(EmptyStatement emptyStatement, BlockScope scope) { + } + public void endVisit(ForStatement forStatement, BlockScope scope) { + } + public void endVisit(IfStatement ifStatement, BlockScope scope) { + } + public void endVisit(ImportReference importRef, CompilationUnitScope scope) { + } + public void endVisit(Initializer initializer, MethodScope scope) { + } + public void endVisit( + InstanceOfExpression instanceOfExpression, + BlockScope scope) { + } + public void endVisit(IntLiteral intLiteral, BlockScope scope) { + } + public void endVisit(LabeledStatement labeledStatement, BlockScope scope) { + } + public void endVisit(LocalDeclaration localDeclaration, BlockScope scope) { + } + public void endVisit(LongLiteral longLiteral, BlockScope scope) { + } + public void endVisit( + MemberTypeDeclaration memberTypeDeclaration, + ClassScope scope) { + } + public void endVisit(MessageSend messageSend, BlockScope scope) { + } + public void endVisit(MethodDeclaration methodDeclaration, ClassScope scope) { + } + public void endVisit(NullLiteral nullLiteral, BlockScope scope) { + } + public void endVisit(OR_OR_Expression or_or_Expression, BlockScope scope) { + } + public void endVisit(PostfixExpression postfixExpression, BlockScope scope) { + } + public void endVisit(PrefixExpression prefixExpression, BlockScope scope) { + } + public void endVisit( + QualifiedAllocationExpression qualifiedAllocationExpression, + BlockScope scope) { + } + public void endVisit( + QualifiedNameReference qualifiedNameReference, + BlockScope scope) { + } + public void endVisit( + QualifiedSuperReference qualifiedSuperReference, + BlockScope scope) { + } + public void endVisit( + QualifiedThisReference qualifiedThisReference, + BlockScope scope) { + } + public void endVisit( + QualifiedTypeReference qualifiedTypeReference, + BlockScope scope) { + } + public void endVisit( + QualifiedTypeReference qualifiedTypeReference, + ClassScope scope) { + } + public void endVisit(ReturnStatement returnStatement, BlockScope scope) { + } + public void endVisit( + SingleNameReference singleNameReference, + BlockScope scope) { + } + public void endVisit( + SingleTypeReference singleTypeReference, + BlockScope scope) { + } + public void endVisit( + SingleTypeReference singleTypeReference, + ClassScope scope) { + } + public void endVisit(StringLiteral stringLiteral, BlockScope scope) { + } + public void endVisit(SuperReference superReference, BlockScope scope) { + } + public void endVisit(SwitchStatement switchStatement, BlockScope scope) { + } + public void endVisit( + SynchronizedStatement synchronizedStatement, + BlockScope scope) { + } + public void endVisit(ThisReference thisReference, BlockScope scope) { + } + public void endVisit(ThrowStatement throwStatement, BlockScope scope) { + } + public void endVisit(TrueLiteral trueLiteral, BlockScope scope) { + } + public void endVisit(TryStatement tryStatement, BlockScope scope) { + } + public void endVisit( + TypeDeclaration typeDeclaration, + CompilationUnitScope scope) { + } + public void endVisit(UnaryExpression unaryExpression, BlockScope scope) { + } + public void endVisit(WhileStatement whileStatement, BlockScope scope) { + } + public boolean visit( + AllocationExpression allocationExpression, + BlockScope scope) { + return true; + } + public boolean visit(AND_AND_Expression and_and_Expression, BlockScope scope) { + return true; + } + public boolean visit( + AnonymousLocalTypeDeclaration anonymousTypeDeclaration, + BlockScope scope) { + return true; + } + public boolean visit(Argument argument, BlockScope scope) { + return true; + } + public boolean visit( + ArrayAllocationExpression arrayAllocationExpression, + BlockScope scope) { + return true; + } + public boolean visit(ArrayInitializer arrayInitializer, BlockScope scope) { + return true; + } + public boolean visit( + ArrayQualifiedTypeReference arrayQualifiedTypeReference, + BlockScope scope) { + return true; + } + public boolean visit( + ArrayQualifiedTypeReference arrayQualifiedTypeReference, + ClassScope scope) { + return true; + } + public boolean visit(ArrayReference arrayReference, BlockScope scope) { + return true; + } + public boolean visit(ArrayTypeReference arrayTypeReference, BlockScope scope) { + return true; + } + public boolean visit(ArrayTypeReference arrayTypeReference, ClassScope scope) { + return true; + } + public boolean visit(Assignment assignment, BlockScope scope) { + return true; + } + public boolean visit(AssertStatement assertStatement, BlockScope scope) { + return true; + } + public boolean visit(BinaryExpression binaryExpression, BlockScope scope) { + return true; + } + public boolean visit(Block block, BlockScope scope) { + return true; + } + public boolean visit(Break breakStatement, BlockScope scope) { + return true; + } + public boolean visit(Case caseStatement, BlockScope scope) { + return true; + } + public boolean visit(CastExpression castExpression, BlockScope scope) { + return true; + } + public boolean visit(CharLiteral charLiteral, BlockScope scope) { + return true; + } + public boolean visit(ClassLiteralAccess classLiteral, BlockScope scope) { + return true; + } + public boolean visit(Clinit clinit, ClassScope scope) { + return true; + } + public boolean visit( + CompilationUnitDeclaration compilationUnitDeclaration, + CompilationUnitScope scope) { + return true; + } + public boolean visit(CompoundAssignment compoundAssignment, BlockScope scope) { + return true; + } + public boolean visit( + ConditionalExpression conditionalExpression, + BlockScope scope) { + return true; + } + public boolean visit( + ConstructorDeclaration constructorDeclaration, + ClassScope scope) { + return true; + } + public boolean visit(Continue continueStatement, BlockScope scope) { + return true; + } + public boolean visit(DefaultCase defaultCaseStatement, BlockScope scope) { + return true; + } + public boolean visit(DoStatement doStatement, BlockScope scope) { + return true; + } + public boolean visit(DoubleLiteral doubleLiteral, BlockScope scope) { + return true; + } + public boolean visit(EqualExpression equalExpression, BlockScope scope) { + return true; + } + public boolean visit(EmptyStatement emptyStatement, BlockScope scope) { + return true; + } + public boolean visit( + ExplicitConstructorCall explicitConstructor, + BlockScope scope) { + return true; + } + public boolean visit( + ExtendedStringLiteral extendedStringLiteral, + BlockScope scope) { + return true; + } + public boolean visit(FalseLiteral falseLiteral, BlockScope scope) { + return true; + } + public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) { + return true; + } + public boolean visit(FieldReference fieldReference, BlockScope scope) { + return true; + } + public boolean visit(FloatLiteral floatLiteral, BlockScope scope) { + return true; + } + public boolean visit(ForStatement forStatement, BlockScope scope) { + return true; + } + public boolean visit(IfStatement ifStatement, BlockScope scope) { + return true; + } + public boolean visit(ImportReference importRef, CompilationUnitScope scope) { + return true; + } + public boolean visit(Initializer initializer, MethodScope scope) { + return true; + } + public boolean visit( + InstanceOfExpression instanceOfExpression, + BlockScope scope) { + return true; + } + public boolean visit(IntLiteral intLiteral, BlockScope scope) { + return true; + } + public boolean visit(LabeledStatement labeledStatement, BlockScope scope) { + return true; + } + public boolean visit(LocalDeclaration localDeclaration, BlockScope scope) { + return true; + } + public boolean visit(LongLiteral longLiteral, BlockScope scope) { + return true; + } + public boolean visit( + MemberTypeDeclaration memberTypeDeclaration, + ClassScope scope) { + return true; + } + public boolean visit(MessageSend messageSend, BlockScope scope) { + return true; + } + public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) { + return true; + } + public boolean visit(NullLiteral nullLiteral, BlockScope scope) { + return true; + } + public boolean visit(OR_OR_Expression or_or_Expression, BlockScope scope) { + return true; + } + public boolean visit(PostfixExpression postfixExpression, BlockScope scope) { + return true; + } + public boolean visit(PrefixExpression prefixExpression, BlockScope scope) { + return true; + } + public boolean visit( + QualifiedAllocationExpression qualifiedAllocationExpression, + BlockScope scope) { + return true; + } + public boolean visit( + QualifiedNameReference qualifiedNameReference, + BlockScope scope) { + return true; + } + public boolean visit( + QualifiedSuperReference qualifiedSuperReference, + BlockScope scope) { + return true; + } + public boolean visit( + QualifiedThisReference qualifiedThisReference, + BlockScope scope) { + return true; + } + public boolean visit( + QualifiedTypeReference qualifiedTypeReference, + BlockScope scope) { + return true; + } + public boolean visit( + QualifiedTypeReference qualifiedTypeReference, + ClassScope scope) { + return true; + } + public boolean visit(ReturnStatement returnStatement, BlockScope scope) { + return true; + } + public boolean visit( + SingleNameReference singleNameReference, + BlockScope scope) { + return true; + } + public boolean visit( + SingleTypeReference singleTypeReference, + BlockScope scope) { + return true; + } + public boolean visit( + SingleTypeReference singleTypeReference, + ClassScope scope) { + return true; + } + public boolean visit(StringLiteral stringLiteral, BlockScope scope) { + return true; + } + public boolean visit(SuperReference superReference, BlockScope scope) { + return true; + } + public boolean visit(SwitchStatement switchStatement, BlockScope scope) { + return true; + } + public boolean visit( + SynchronizedStatement synchronizedStatement, + BlockScope scope) { + return true; + } + public boolean visit(ThisReference thisReference, BlockScope scope) { + return true; + } + public boolean visit(ThrowStatement throwStatement, BlockScope scope) { + return true; + } + public boolean visit(TrueLiteral trueLiteral, BlockScope scope) { + return true; + } + public boolean visit(TryStatement tryStatement, BlockScope scope) { + return true; + } + public boolean visit( + TypeDeclaration typeDeclaration, + CompilationUnitScope scope) { + return true; + } + public boolean visit(UnaryExpression unaryExpression, BlockScope scope) { + return true; + } + public boolean visit(WhileStatement whileStatement, BlockScope scope) { + return true; + } + public boolean visit( + LocalTypeDeclaration localTypeDeclaration, + BlockScope scope) { + return true; + } + public void endVisit( + LocalTypeDeclaration localTypeDeclaration, + BlockScope scope) { + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ClassFile.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ClassFile.java new file mode 100644 index 0000000..db85327 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ClassFile.java @@ -0,0 +1,2959 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler; + +import java.io.*; +import java.util.*; + +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.core.compiler.*; +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; +import net.sourceforge.phpdt.internal.compiler.util.*; + +/** + * Represents a class file wrapper on bytes, it is aware of its actual + * type name. + * + * Public APIs are listed below: + * + * byte[] getBytes(); + * Answer the actual bytes of the class file + * + * char[][] getCompoundName(); + * Answer the compound name of the class file. + * For example, {{java}, {util}, {Hashtable}}. + * + * byte[] getReducedBytes(); + * Answer a smaller byte format, which is only contains some structural + * information. Those bytes are decodable with a regular class file reader, + * such as DietClassFileReader + */ +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; + // the header contains all the bytes till the end of the constant pool + public byte[] contents; + // that collection contains all the remaining bytes of the .class file + public int headerOffset; + public int contentsOffset; + public int constantPoolOffset; + public int methodCountOffset; + public int methodCount; + protected boolean creatingProblemType; + public static final int INITIAL_CONTENTS_SIZE = 1000; + public static final int INITIAL_HEADER_SIZE = 1000; + public static final int INCREMENT_SIZE = 1000; + public static final int INNER_CLASSES_SIZE = 5; + protected HashtableOfType nameUsage; + public CodeStream codeStream; + protected int problemLine; // used to create line number attributes for problem methods + + /** + * INTERNAL USE-ONLY + * This methods creates a new instance of the receiver. + */ + public ClassFile() { + } + + /** + * 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.ClassFile + * @param creatingProblemType boolean + */ + public ClassFile( + SourceTypeBinding aType, + ClassFile enclosingClassFile, + boolean creatingProblemType) { + referenceBinding = aType; + header = new byte[INITIAL_HEADER_SIZE]; + // generate the magic numbers inside the header + header[headerOffset++] = (byte) (0xCAFEBABEL >> 24); + header[headerOffset++] = (byte) (0xCAFEBABEL >> 16); + header[headerOffset++] = (byte) (0xCAFEBABEL >> 8); + header[headerOffset++] = (byte) (0xCAFEBABEL >> 0); + switch(((SourceTypeBinding) referenceBinding).scope.environment().options.targetJDK) { + case CompilerOptions.JDK1_4 : + // Compatible with JDK 1.4 + header[headerOffset++] = 0; + header[headerOffset++] = 0; + header[headerOffset++] = 0; + header[headerOffset++] = 48; + break; + case CompilerOptions.JDK1_3 : + // Compatible with JDK 1.3 + header[headerOffset++] = 0; + header[headerOffset++] = 0; + header[headerOffset++] = 0; + header[headerOffset++] = 47; + break; + case CompilerOptions.JDK1_2 : + // Compatible with JDK 1.2 + header[headerOffset++] = 0; + header[headerOffset++] = 0; + header[headerOffset++] = 0; + header[headerOffset++] = 46; + break; + case CompilerOptions.JDK1_1 : + // Compatible with JDK 1.1 + header[headerOffset++] = 0; + header[headerOffset++] = 3; + header[headerOffset++] = 0; + header[headerOffset++] = 45; + } + constantPoolOffset = headerOffset; + headerOffset += 2; + constantPool = new ConstantPool(this); + + // Modifier manipulations for classfile + int accessFlags = aType.getAccessFlags(); + if (aType.isPrivate()) { // rewrite private to non-public + accessFlags &= ~AccPublic; + } + if (aType.isProtected()) { // rewrite protected into public + accessFlags |= AccPublic; + } + // clear all bits that are illegal for a class or an interface + accessFlags + &= ~( + AccStrictfp + | AccProtected + | AccPrivate + | AccStatic + | AccSynchronized + | AccNative); + + // set the AccSuper flag (has to be done after clearing AccSynchronized - since same value) + accessFlags |= AccSuper; + + this.enclosingClassFile = enclosingClassFile; + // innerclasses get their names computed at code gen time + if (aType.isLocalType()) { + ((LocalTypeBinding) aType).constantPoolName( + computeConstantPoolName((LocalTypeBinding) aType)); + ReferenceBinding[] memberTypes = aType.memberTypes(); + for (int i = 0, max = memberTypes.length; i < max; i++) { + ((LocalTypeBinding) memberTypes[i]).constantPoolName( + computeConstantPoolName((LocalTypeBinding) memberTypes[i])); + } + } + contents = new byte[INITIAL_CONTENTS_SIZE]; + // 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); + contents[contentsOffset++] = (byte) (classNameIndex >> 8); + contents[contentsOffset++] = (byte) classNameIndex; + int superclassNameIndex; + if (aType.isInterface()) { + superclassNameIndex = constantPool.literalIndexForJavaLangObject(); + } else { + superclassNameIndex = + (aType.superclass == null ? 0 : constantPool.literalIndex(aType.superclass)); + } + contents[contentsOffset++] = (byte) (superclassNameIndex >> 8); + contents[contentsOffset++] = (byte) superclassNameIndex; + ReferenceBinding[] superInterfacesBinding = aType.superInterfaces(); + int interfacesCount = superInterfacesBinding.length; + contents[contentsOffset++] = (byte) (interfacesCount >> 8); + contents[contentsOffset++] = (byte) interfacesCount; + if (superInterfacesBinding != null) { + for (int i = 0; i < interfacesCount; i++) { + int interfaceIndex = constantPool.literalIndex(superInterfacesBinding[i]); + contents[contentsOffset++] = (byte) (interfaceIndex >> 8); + contents[contentsOffset++] = (byte) interfaceIndex; + } + } + produceDebugAttributes = + ((SourceTypeBinding) referenceBinding) + .scope + .environment() + .options + .produceDebugAttributes; + innerClassesBindings = new ReferenceBinding[INNER_CLASSES_SIZE]; + this.creatingProblemType = creatingProblemType; + 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) + ClassFile outermostClassFile = this.outerMostEnclosingClassFile(); + if (this == outermostClassFile) { + codeStream.maxFieldCount = aType.scope.referenceType().maxFieldCount; + } else { + codeStream.maxFieldCount = outermostClassFile.codeStream.maxFieldCount; + } + } + + /** + * INTERNAL USE-ONLY + * Generate the byte for a problem method info that correspond to a boggus method. + * + * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration + * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding + */ + public void addAbstractMethod( + AbstractMethodDeclaration method, + MethodBinding methodBinding) { + + // force the modifiers to be public and abstract + methodBinding.modifiers = AccPublic | AccAbstract; + + this.generateMethodInfoHeader(methodBinding); + int methodAttributeOffset = this.contentsOffset; + int attributeNumber = this.generateMethodInfoAttribute(methodBinding); + this.completeMethodInfo(methodAttributeOffset, attributeNumber); + } + + /** + * INTERNAL USE-ONLY + * This methods generate all the attributes for the receiver. + * For a class they could be: + * - source file attribute + * - inner classes attribute + * - deprecated attribute + */ + public void addAttributes() { + // update the method count + contents[methodCountOffset++] = (byte) (methodCount >> 8); + contents[methodCountOffset] = (byte) methodCount; + + int attributeNumber = 0; + // leave two bytes for the number of attributes and store the current offset + int attributeOffset = contentsOffset; + contentsOffset += 2; + int contentsLength; + + // source attribute + if ((produceDebugAttributes & CompilerOptions.Source) != 0) { + String fullFileName = + new String(referenceBinding.scope.referenceCompilationUnit().getFileName()); + fullFileName = fullFileName.replace('\\', '/'); + int lastIndex = fullFileName.lastIndexOf('/'); + if (lastIndex != -1) { + fullFileName = fullFileName.substring(lastIndex + 1, fullFileName.length()); + } + // check that there is enough space to write all the bytes for the field info corresponding + // to the @fieldBinding + if (contentsOffset + 8 >= (contentsLength = contents.length)) { + System.arraycopy( + contents, + 0, + (contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + int sourceAttributeNameIndex = + constantPool.literalIndex(AttributeNamesConstants.SourceName); + contents[contentsOffset++] = (byte) (sourceAttributeNameIndex >> 8); + contents[contentsOffset++] = (byte) sourceAttributeNameIndex; + // The length of a source file attribute is 2. This is a fixed-length + // attribute + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 2; + // write the source file name + int fileNameIndex = constantPool.literalIndex(fullFileName.toCharArray()); + contents[contentsOffset++] = (byte) (fileNameIndex >> 8); + contents[contentsOffset++] = (byte) fileNameIndex; + attributeNumber++; + } + // Deprecated attribute + if (referenceBinding.isDeprecated()) { + // check that there is enough space to write all the bytes for the field info corresponding + // to the @fieldBinding + if (contentsOffset + 6 >= (contentsLength = contents.length)) { + System.arraycopy( + contents, + 0, + (contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + int deprecatedAttributeNameIndex = + constantPool.literalIndex(AttributeNamesConstants.DeprecatedName); + contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8); + contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex; + // the length of a deprecated attribute is equals to 0 + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + attributeNumber++; + } + // Inner class attribute + if (numberOfInnerClasses != 0) { + // Generate the inner class attribute + int exSize; + if (contentsOffset + (exSize = (8 * numberOfInnerClasses + 8)) + >= (contentsLength = contents.length)) { + System.arraycopy( + contents, + 0, + (contents = + new byte[contentsLength + + (exSize >= INCREMENT_SIZE ? exSize : INCREMENT_SIZE)]), + 0, + contentsLength); + } + // Now we now the size of the attribute and the number of entries + // attribute name + int attributeNameIndex = + constantPool.literalIndex(AttributeNamesConstants.InnerClassName); + contents[contentsOffset++] = (byte) (attributeNameIndex >> 8); + contents[contentsOffset++] = (byte) attributeNameIndex; + int value = (numberOfInnerClasses << 3) + 2; + contents[contentsOffset++] = (byte) (value >> 24); + contents[contentsOffset++] = (byte) (value >> 16); + contents[contentsOffset++] = (byte) (value >> 8); + contents[contentsOffset++] = (byte) value; + contents[contentsOffset++] = (byte) (numberOfInnerClasses >> 8); + contents[contentsOffset++] = (byte) numberOfInnerClasses; + for (int i = 0; i < numberOfInnerClasses; i++) { + ReferenceBinding innerClass = innerClassesBindings[i]; + int accessFlags = innerClass.getAccessFlags(); + int innerClassIndex = constantPool.literalIndex(innerClass); + // 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()); + contents[contentsOffset++] = (byte) (outerClassIndex >> 8); + contents[contentsOffset++] = (byte) outerClassIndex; + } else { + // equals to 0 if the innerClass is not a member type + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + } + // name index + if (!innerClass.isAnonymousType()) { + int nameIndex = constantPool.literalIndex(innerClass.sourceName()); + contents[contentsOffset++] = (byte) (nameIndex >> 8); + contents[contentsOffset++] = (byte) nameIndex; + } else { + // equals to 0 if the innerClass is an anonymous type + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + } + // access flag + if (innerClass.isAnonymousType()) { + accessFlags |= AccPrivate; + } else + if (innerClass.isLocalType() && !innerClass.isMemberType()) { + accessFlags |= AccPrivate; + } + contents[contentsOffset++] = (byte) (accessFlags >> 8); + contents[contentsOffset++] = (byte) accessFlags; + } + attributeNumber++; + } + // update the number of attributes + contentsLength = contents.length; + if (attributeOffset + 2 >= contentsLength) { + System.arraycopy( + contents, + 0, + (contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + contents[attributeOffset++] = (byte) (attributeNumber >> 8); + contents[attributeOffset] = (byte) attributeNumber; + + // resynchronize all offsets of the classfile + header = constantPool.poolContent; + headerOffset = constantPool.currentOffset; + int constantPoolCount = constantPool.currentIndex; + header[constantPoolOffset++] = (byte) (constantPoolCount >> 8); + header[constantPoolOffset] = (byte) constantPoolCount; + } + + /** + * INTERNAL USE-ONLY + * This methods generate all the default abstract method infos that correpond to + * the abstract methods inherited from superinterfaces. + */ + public void addDefaultAbstractMethods() { // default abstract methods + MethodBinding[] defaultAbstractMethods = + 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); + } + } + + /** + * 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 + int contentsLength; + if (contentsOffset + 30 >= (contentsLength = contents.length)) { + System.arraycopy( + contents, + 0, + (contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + // 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; + // 4.7.2 only static constant fields get a ConstantAttribute + if (fieldBinding.constant != Constant.NotAConstant + && fieldBinding.constant.typeID() != T_null) { + // Now we generate the constant attribute corresponding to the fieldBinding + int constantValueNameIndex = + constantPool.literalIndex(AttributeNamesConstants.ConstantValueName); + contents[contentsOffset++] = (byte) (constantValueNameIndex >> 8); + contents[contentsOffset++] = (byte) constantValueNameIndex; + // The attribute length = 2 in case of a constantValue attribute + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 2; + attributeNumber++; + // Need to add the constant_value_index + switch (fieldBinding.constant.typeID()) { + case T_boolean : + int booleanValueIndex = + constantPool.literalIndex(fieldBinding.constant.booleanValue() ? 1 : 0); + contents[contentsOffset++] = (byte) (booleanValueIndex >> 8); + contents[contentsOffset++] = (byte) booleanValueIndex; + break; + case T_byte : + case T_char : + case T_int : + case T_short : + int integerValueIndex = + constantPool.literalIndex(fieldBinding.constant.intValue()); + contents[contentsOffset++] = (byte) (integerValueIndex >> 8); + contents[contentsOffset++] = (byte) integerValueIndex; + break; + case T_float : + int floatValueIndex = + constantPool.literalIndex(fieldBinding.constant.floatValue()); + contents[contentsOffset++] = (byte) (floatValueIndex >> 8); + contents[contentsOffset++] = (byte) floatValueIndex; + break; + case T_double : + int doubleValueIndex = + constantPool.literalIndex(fieldBinding.constant.doubleValue()); + contents[contentsOffset++] = (byte) (doubleValueIndex >> 8); + contents[contentsOffset++] = (byte) doubleValueIndex; + break; + case T_long : + int longValueIndex = + constantPool.literalIndex(fieldBinding.constant.longValue()); + contents[contentsOffset++] = (byte) (longValueIndex >> 8); + contents[contentsOffset++] = (byte) longValueIndex; + break; + case T_String : + int stringValueIndex = + constantPool.literalIndex( + ((StringConstant) fieldBinding.constant).stringValue()); + if (stringValueIndex == -1) { + if (!creatingProblemType) { + // report an error and abort: will lead to a problem type classfile creation + TypeDeclaration typeDeclaration = referenceBinding.scope.referenceContext; + FieldDeclaration[] fieldDecls = typeDeclaration.fields; + for (int i = 0, max = fieldDecls.length; i < max; i++) { + if (fieldDecls[i].binding == fieldBinding) { + // problem should abort + typeDeclaration.scope.problemReporter().stringConstantIsExceedingUtf8Limit( + fieldDecls[i]); + } + } + } 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--; + } + } else { + contents[contentsOffset++] = (byte) (stringValueIndex >> 8); + contents[contentsOffset++] = (byte) stringValueIndex; + } + } + } + if (fieldBinding.isSynthetic()) { + 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; + attributeNumber++; + } + if (fieldBinding.isDeprecated()) { + int deprecatedAttributeNameIndex = + constantPool.literalIndex(AttributeNamesConstants.DeprecatedName); + contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8); + contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex; + // the length of a deprecated attribute is equals to 0 + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + attributeNumber++; + } + contents[fieldAttributeOffset++] = (byte) (attributeNumber >> 8); + contents[fieldAttributeOffset] = (byte) attributeNumber; + } + + /** + * 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(); + int fieldCount = + currentBinding.fieldCount() + + (syntheticFields == null ? 0 : syntheticFields.length); + + // write the number of fields + contents[contentsOffset++] = (byte) (fieldCount >> 8); + contents[contentsOffset++] = (byte) fieldCount; + + FieldBinding[] fieldBindings = currentBinding.fields(); + for (int i = 0, max = fieldBindings.length; i < max; i++) { + addFieldInfo(fieldBindings[i]); + } + if (syntheticFields != null) { + for (int i = 0, max = syntheticFields.length; i < max; i++) { + addFieldInfo(syntheticFields[i]); + } + } + } + + /** + * INTERNAL USE-ONLY + * This methods stores the bindings for each inner class. They will be used to know which entries + * have to be generated for the inner classes attributes. + * @param referenceBinding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding + */ + public void addInnerClasses(ReferenceBinding referenceBinding) { + // check first if that reference binding is there + for (int i = 0; i < numberOfInnerClasses; i++) { + if (innerClassesBindings[i] == referenceBinding) + return; + } + int length = innerClassesBindings.length; + if (numberOfInnerClasses == length) { + System.arraycopy( + innerClassesBindings, + 0, + (innerClassesBindings = new ReferenceBinding[length * 2]), + 0, + length); + } + innerClassesBindings[numberOfInnerClasses++] = referenceBinding; + } + + /** + * INTERNAL USE-ONLY + * Generate the byte for a problem clinit method info that correspond to a boggus method. + * + * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[] + */ + public void addProblemClinit(IProblem[] problems) { + generateMethodInfoHeaderForClinit(); + // leave two spaces for the number of attributes + contentsOffset -= 2; + int attributeOffset = contentsOffset; + contentsOffset += 2; + int attributeNumber = 0; + + int codeAttributeOffset = contentsOffset; + generateCodeAttributeHeader(); + codeStream.resetForProblemClinit(this); + String problemString = "" ; //$NON-NLS-1$ + if (problems != null) { + int max = problems.length; + StringBuffer buffer = new StringBuffer(25); + int count = 0; + for (int i = 0; i < max; i++) { + IProblem problem = problems[i]; + if ((problem != null) && (problem.isError())) { + buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$ + count++; + if (problemLine == 0) { + problemLine = problem.getSourceLineNumber(); + } + problems[i] = null; + } + } // insert the top line afterwards, once knowing how many problems we have to consider + if (count > 1) { + buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$ + } else { + buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$ + } + problemString = buffer.toString(); + } + + // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "") + int[] exceptionHandler = + codeStream.generateCodeAttributeForProblemMethod( + referenceBinding + .scope + .environment() + .options + .runtimeExceptionNameForCompileError, + problemString); + attributeNumber++; // code attribute + completeCodeAttributeForClinit( + codeAttributeOffset, + exceptionHandler, + referenceBinding + .scope + .referenceCompilationUnit() + .compilationResult + .lineSeparatorPositions); + contents[attributeOffset++] = (byte) (attributeNumber >> 8); + contents[attributeOffset] = (byte) attributeNumber; + } + + /** + * INTERNAL USE-ONLY + * Generate the byte for a problem method info that correspond to a boggus constructor. + * + * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration + * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding + * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[] + */ + public void addProblemConstructor( + AbstractMethodDeclaration method, + MethodBinding methodBinding, + IProblem[] problems) { + + // always clear the strictfp/native/abstract bit for a problem method + methodBinding.modifiers &= ~(AccStrictfp | AccNative | AccAbstract); + + generateMethodInfoHeader(methodBinding); + int methodAttributeOffset = contentsOffset; + int attributeNumber = generateMethodInfoAttribute(methodBinding); + + // Code attribute + attributeNumber++; + int codeAttributeOffset = contentsOffset; + generateCodeAttributeHeader(); + final ProblemReporter problemReporter = method.scope.problemReporter(); + codeStream.reset(method, this); + String problemString = "" ; //$NON-NLS-1$ + if (problems != null) { + int max = problems.length; + StringBuffer buffer = new StringBuffer(25); + int count = 0; + for (int i = 0; i < max; i++) { + IProblem problem = problems[i]; + if ((problem != null) && (problem.isError())) { + buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$ + count++; + if (problemLine == 0) { + problemLine = problem.getSourceLineNumber(); + } + } + } // insert the top line afterwards, once knowing how many problems we have to consider + if (count > 1) { + buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$ + } else { + buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$ + } + problemString = buffer.toString(); + } + + // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "") + int[] exceptionHandler = + codeStream.generateCodeAttributeForProblemMethod( + problemReporter.options.runtimeExceptionNameForCompileError, + problemString); + completeCodeAttributeForProblemMethod( + method, + methodBinding, + codeAttributeOffset, + exceptionHandler, + ((SourceTypeBinding) methodBinding.declaringClass) + .scope + .referenceCompilationUnit() + .compilationResult + .lineSeparatorPositions); + completeMethodInfo(methodAttributeOffset, attributeNumber); + } + + /** + * INTERNAL USE-ONLY + * Generate the byte for a problem method info that correspond to a boggus constructor. + * Reset the position inside the contents byte array to the savedOffset. + * + * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration + * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding + * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[] + * @param savedOffset int + */ + public void addProblemConstructor( + AbstractMethodDeclaration method, + MethodBinding methodBinding, + IProblem[] problems, + 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 + addProblemConstructor(method, methodBinding, problems); + } + + /** + * INTERNAL USE-ONLY + * Generate the byte for a problem method info that correspond to a boggus method. + * + * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration + * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding + * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[] + */ + public void addProblemMethod( + AbstractMethodDeclaration method, + MethodBinding methodBinding, + IProblem[] problems) { + if (methodBinding.isAbstract() && methodBinding.declaringClass.isInterface()) { + method.abort(AbstractMethodDeclaration.AbortType); + } + // always clear the strictfp/native/abstract bit for a problem method + methodBinding.modifiers &= ~(AccStrictfp | AccNative | AccAbstract); + + generateMethodInfoHeader(methodBinding); + int methodAttributeOffset = contentsOffset; + int attributeNumber = generateMethodInfoAttribute(methodBinding); + + // Code attribute + attributeNumber++; + + int codeAttributeOffset = contentsOffset; + generateCodeAttributeHeader(); + final ProblemReporter problemReporter = method.scope.problemReporter(); + codeStream.reset(method, this); + String problemString = "" ; //$NON-NLS-1$ + if (problems != null) { + int max = problems.length; + StringBuffer buffer = new StringBuffer(25); + int count = 0; + for (int i = 0; i < max; i++) { + IProblem problem = problems[i]; + if ((problem != null) + && (problem.isError()) + && (problem.getSourceStart() >= method.declarationSourceStart) + && (problem.getSourceEnd() <= method.declarationSourceEnd)) { + buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$ + count++; + if (problemLine == 0) { + problemLine = problem.getSourceLineNumber(); + } + problems[i] = null; + } + } // insert the top line afterwards, once knowing how many problems we have to consider + if (count > 1) { + buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$ + } else { + buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$ + } + problemString = buffer.toString(); + } + + // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "") + int[] exceptionHandler = + codeStream.generateCodeAttributeForProblemMethod( + problemReporter.options.runtimeExceptionNameForCompileError, + problemString); + completeCodeAttributeForProblemMethod( + method, + methodBinding, + codeAttributeOffset, + exceptionHandler, + ((SourceTypeBinding) methodBinding.declaringClass) + .scope + .referenceCompilationUnit() + .compilationResult + .lineSeparatorPositions); + completeMethodInfo(methodAttributeOffset, attributeNumber); + } + + /** + * INTERNAL USE-ONLY + * Generate the byte for a problem method info that correspond to a boggus method. + * Reset the position inside the contents byte array to the savedOffset. + * + * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration + * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding + * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[] + * @param savedOffset int + */ + public void addProblemMethod( + AbstractMethodDeclaration method, + MethodBinding methodBinding, + IProblem[] problems, + 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 private field + addSyntheticFieldReadAccessMethod(syntheticAccessMethods[i]); + break; + case SyntheticAccessMethodBinding.FieldWriteAccess : + // generate a method info to emulate an writing access to + // a private field + addSyntheticFieldWriteAccessMethod(syntheticAccessMethods[i]); + break; + case SyntheticAccessMethodBinding.MethodAccess : + // generate a method info to emulate an access to a private method + addSyntheticMethodAccessMethod(syntheticAccessMethods[i]); + break; + case SyntheticAccessMethodBinding.ConstructorAccess : + // generate a method info to emulate an access to a private method + 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 + methodBinding.modifiers &= ~(AccStrictfp | AccNative | AccAbstract); + + generateMethodInfoHeader(methodBinding); + 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(); + + final ProblemReporter problemReporter = methodDeclaration.scope.problemReporter(); + codeStream.init(this); + codeStream.preserveUnusedLocals = true; + codeStream.initializeMaxLocals(methodBinding); + + // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "") + int[] exceptionHandler = + codeStream.generateCodeAttributeForProblemMethod( + problemReporter.options.runtimeExceptionNameForCompileError, + problemString); + + completeCodeAttributeForMissingAbstractProblemMethod( + methodBinding, + codeAttributeOffset, + exceptionHandler, + compilationResult.lineSeparatorPositions); + + completeMethodInfo(methodAttributeOffset, attributeNumber); + } + + /** + * + */ + public void completeCodeAttributeForMissingAbstractProblemMethod( + MethodBinding binding, + int codeAttributeOffset, + int[] exceptionHandler, + int[] startLineIndexes) { + // reinitialize the localContents with the byte modified by the code stream + byte[] localContents = 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; + localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); + localContents[codeAttributeOffset + 7] = (byte) max_stack; + int max_locals = codeStream.maxLocals; + localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); + localContents[codeAttributeOffset + 9] = (byte) max_locals; + int code_length = codeStream.position; + localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24); + localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16); + localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8); + localContents[codeAttributeOffset + 13] = (byte) code_length; + // write the exception table + int contentsLength; + if (localContentsOffset + 50 >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 1; + int start = exceptionHandler[0]; + localContents[localContentsOffset++] = (byte) (start >> 8); + localContents[localContentsOffset++] = (byte) start; + int end = exceptionHandler[1]; + localContents[localContentsOffset++] = (byte) (end >> 8); + localContents[localContentsOffset++] = (byte) end; + int handlerPC = exceptionHandler[2]; + localContents[localContentsOffset++] = (byte) (handlerPC >> 8); + localContents[localContentsOffset++] = (byte) handlerPC; + int nameIndex = constantPool.literalIndexForJavaLangException(); + localContents[localContentsOffset++] = (byte) (nameIndex >> 8); + localContents[localContentsOffset++] = (byte) nameIndex; // 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); + localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8); + localContents[localContentsOffset++] = (byte) lineNumberNameIndex; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 6; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 1; + if (problemLine == 0) { + problemLine = searchLineNumber(startLineIndexes, binding.sourceStart()); + } + // first entry at pc = 0 + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = (byte) (problemLine >> 8); + localContents[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 + >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8); + localContents[codeAttributeAttributeOffset] = (byte) attributeNumber; + // update the attribute length + int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6); + localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); + localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); + localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); + localContents[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. + * + * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding + */ + public void addSyntheticConstructorAccessMethod(SyntheticAccessMethodBinding methodBinding) { + generateMethodInfoHeader(methodBinding); + // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 2; + // Code attribute + int codeAttributeOffset = contentsOffset; + generateCodeAttributeHeader(); + codeStream.init(this); + codeStream.generateSyntheticBodyForConstructorAccess(methodBinding); + completeCodeAttributeForSyntheticAccessMethod( + 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) { + generateMethodInfoHeader(methodBinding); + // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 2; + // Code attribute + int codeAttributeOffset = contentsOffset; + generateCodeAttributeHeader(); + codeStream.init(this); + codeStream.generateSyntheticBodyForFieldReadAccess(methodBinding); + completeCodeAttributeForSyntheticAccessMethod( + 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 write access to a private field. + * + * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding + */ + public void addSyntheticFieldWriteAccessMethod(SyntheticAccessMethodBinding methodBinding) { + generateMethodInfoHeader(methodBinding); + // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 2; + // Code attribute + int codeAttributeOffset = contentsOffset; + generateCodeAttributeHeader(); + codeStream.init(this); + codeStream.generateSyntheticBodyForFieldWriteAccess(methodBinding); + completeCodeAttributeForSyntheticAccessMethod( + 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 access to a private method. + * + * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding + */ + public void addSyntheticMethodAccessMethod(SyntheticAccessMethodBinding methodBinding) { + generateMethodInfoHeader(methodBinding); + // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 2; + // Code attribute + int codeAttributeOffset = contentsOffset; + generateCodeAttributeHeader(); + codeStream.init(this); + codeStream.generateSyntheticBodyForMethodAccess(methodBinding); + completeCodeAttributeForSyntheticAccessMethod( + 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 + * 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 + * - max_locals + * - code_length + * - exception table + * - and debug attributes if necessary. + * + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param codeAttributeOffset int + */ + public void completeCodeAttribute(int codeAttributeOffset) { + // reinitialize the localContents with the byte modified by the code stream + byte[] localContents = 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 contentsLength; + int code_length = codeStream.position; + if (code_length > 65535) { + codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit( + codeStream.methodDeclaration); + } + if (localContentsOffset + 20 >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + int max_stack = codeStream.stackMax; + localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); + localContents[codeAttributeOffset + 7] = (byte) max_stack; + int max_locals = codeStream.maxLocals; + localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); + localContents[codeAttributeOffset + 9] = (byte) max_locals; + localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24); + localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16); + localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8); + localContents[codeAttributeOffset + 13] = (byte) code_length; + + // write the exception table + int exceptionHandlersNumber = codeStream.exceptionHandlersNumber; + ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers; + int exSize; + if (localContentsOffset + (exSize = (exceptionHandlersNumber * 8 + 2)) + >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = + contents = + new byte[contentsLength + (exSize > INCREMENT_SIZE ? exSize : INCREMENT_SIZE)]), + 0, + contentsLength); + } + // there is no exception table, so we need to offset by 2 the current offset and move + // on the attribute generation + localContents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8); + localContents[localContentsOffset++] = (byte) exceptionHandlersNumber; + for (int i = 0; i < exceptionHandlersNumber; i++) { + ExceptionLabel exceptionHandler = exceptionHandlers[i]; + int start = exceptionHandler.start; + localContents[localContentsOffset++] = (byte) (start >> 8); + localContents[localContentsOffset++] = (byte) start; + int end = exceptionHandler.end; + localContents[localContentsOffset++] = (byte) (end >> 8); + localContents[localContentsOffset++] = (byte) end; + int handlerPC = exceptionHandler.position; + localContents[localContentsOffset++] = (byte) (handlerPC >> 8); + localContents[localContentsOffset++] = (byte) handlerPC; + if (exceptionHandler.exceptionType == null) { + // any exception handler + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 0; + } else { + int nameIndex; + if (exceptionHandler.exceptionType == TypeBinding.NullBinding) { + /* represents ClassNotFoundException, see class literal access*/ + nameIndex = constantPool.literalIndexForJavaLangClassNotFoundException(); + } else { + nameIndex = constantPool.literalIndex(exceptionHandler.exceptionType); + } + localContents[localContentsOffset++] = (byte) (nameIndex >> 8); + localContents[localContentsOffset++] = (byte) nameIndex; + } + } + // 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[] pcToSourceMapTable; + if (((pcToSourceMapTable = codeStream.pcToSourceMap) != null) + && (codeStream.pcToSourceMapSize != 0)) { + int lineNumberNameIndex = + constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName); + if (localContentsOffset + 8 >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8); + localContents[localContentsOffset++] = (byte) lineNumberNameIndex; + int lineNumberTableOffset = localContentsOffset; + localContentsOffset += 6; + // leave space for attribute_length and line_number_table_length + int numberOfEntries = 0; + int length = codeStream.pcToSourceMapSize; + for (int i = 0; i < length;) { + // write the entry + if (localContentsOffset + 4 >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + int pc = pcToSourceMapTable[i++]; + localContents[localContentsOffset++] = (byte) (pc >> 8); + localContents[localContentsOffset++] = (byte) pc; + int lineNumber = pcToSourceMapTable[i++]; + localContents[localContentsOffset++] = (byte) (lineNumber >> 8); + localContents[localContentsOffset++] = (byte) lineNumber; + numberOfEntries++; + } + // now we change the size of the line number attribute + int lineNumberAttr_length = numberOfEntries * 4 + 2; + localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24); + localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16); + localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8); + localContents[lineNumberTableOffset++] = (byte) lineNumberAttr_length; + localContents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8); + localContents[lineNumberTableOffset++] = (byte) numberOfEntries; + attributeNumber++; + } + } + // then we do the local variable attribute + if (codeStream.generateLocalVariableTableAttributes) { + int localVariableTableOffset = localContentsOffset; + int numberOfEntries = 0; + int localVariableNameIndex = + constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName); + if (localContentsOffset + 8 >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8); + localContents[localContentsOffset++] = (byte) localVariableNameIndex; + localContentsOffset += 6; + // leave space for attribute_length and local_variable_table_length + int nameIndex; + int descriptorIndex; + if (!codeStream.methodDeclaration.isStatic()) { + numberOfEntries++; + if (localContentsOffset + 10 >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + localContentsOffset += 2; // the startPC for this is always 0 + localContents[localContentsOffset++] = (byte) (code_length >> 8); + localContents[localContentsOffset++] = (byte) code_length; + nameIndex = constantPool.literalIndex(QualifiedNamesConstants.This); + localContents[localContentsOffset++] = (byte) (nameIndex >> 8); + localContents[localContentsOffset++] = (byte) nameIndex; + descriptorIndex = + constantPool.literalIndex( + codeStream.methodDeclaration.binding.declaringClass.signature()); + localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8); + localContents[localContentsOffset++] = (byte) descriptorIndex; + localContentsOffset += 2; // the resolved position for this is always 0 + } + for (int i = 0; i < codeStream.allLocalsCounter; i++) { + LocalVariableBinding localVariable = codeStream.locals[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 + if (endPC == -1) { + localVariable.declaringScope.problemReporter().abortDueToInternalError( + Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$ + (AstNode) localVariable.declaringScope.methodScope().referenceContext); + } + if (localContentsOffset + 10 >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + // now we can safely add the local entry + numberOfEntries++; + localContents[localContentsOffset++] = (byte) (startPC >> 8); + localContents[localContentsOffset++] = (byte) startPC; + int length = endPC - startPC; + localContents[localContentsOffset++] = (byte) (length >> 8); + localContents[localContentsOffset++] = (byte) length; + nameIndex = constantPool.literalIndex(localVariable.name); + localContents[localContentsOffset++] = (byte) (nameIndex >> 8); + localContents[localContentsOffset++] = (byte) nameIndex; + descriptorIndex = constantPool.literalIndex(localVariable.type.signature()); + localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8); + localContents[localContentsOffset++] = (byte) descriptorIndex; + int resolvedPosition = localVariable.resolvedPosition; + localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8); + localContents[localContentsOffset++] = (byte) resolvedPosition; + } + } + } + int value = numberOfEntries * 10 + 2; + localVariableTableOffset += 2; + localContents[localVariableTableOffset++] = (byte) (value >> 24); + localContents[localVariableTableOffset++] = (byte) (value >> 16); + localContents[localVariableTableOffset++] = (byte) (value >> 8); + localContents[localVariableTableOffset++] = (byte) value; + localContents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8); + localContents[localVariableTableOffset] = (byte) numberOfEntries; + attributeNumber++; + } + // update the number of attributes + // ensure first that there is enough space available inside the localContents array + if (codeAttributeAttributeOffset + 2 + >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8); + localContents[codeAttributeAttributeOffset] = (byte) attributeNumber; + + // update the attribute length + int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6); + localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); + localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); + localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); + localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength; + contentsOffset = localContentsOffset; + } + + /** + * INTERNAL USE-ONLY + * That method completes the creation of the code attribute by setting + * - the attribute_length + * - max_stack + * - max_locals + * - code_length + * - exception table + * - and debug attributes if necessary. + * + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param codeAttributeOffset int + */ + public void completeCodeAttributeForClinit(int codeAttributeOffset) { + // reinitialize the contents with the byte modified by the code stream + byte[] localContents = contents = codeStream.bCodeStream; + int localContentsOffset = codeStream.classFileOffset; + // codeAttributeOffset is the position inside contents 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 contentsLength; + int code_length = codeStream.position; + if (code_length > 65535) { + codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit( + codeStream.methodDeclaration.scope.referenceType()); + } + if (localContentsOffset + 20 >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + int max_stack = codeStream.stackMax; + localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); + localContents[codeAttributeOffset + 7] = (byte) max_stack; + int max_locals = codeStream.maxLocals; + localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); + localContents[codeAttributeOffset + 9] = (byte) max_locals; + localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24); + localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16); + localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8); + localContents[codeAttributeOffset + 13] = (byte) code_length; + + // write the exception table + int exceptionHandlersNumber = codeStream.exceptionHandlersNumber; + ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers; + int exSize; + if (localContentsOffset + (exSize = (exceptionHandlersNumber * 8 + 2)) + >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = + contents = + new byte[contentsLength + (exSize > INCREMENT_SIZE ? exSize : INCREMENT_SIZE)]), + 0, + contentsLength); + } + // there is no exception table, so we need to offset by 2 the current offset and move + // on the attribute generation + localContents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8); + localContents[localContentsOffset++] = (byte) exceptionHandlersNumber; + for (int i = 0; i < exceptionHandlersNumber; i++) { + ExceptionLabel exceptionHandler = exceptionHandlers[i]; + int start = exceptionHandler.start; + localContents[localContentsOffset++] = (byte) (start >> 8); + localContents[localContentsOffset++] = (byte) start; + int end = exceptionHandler.end; + localContents[localContentsOffset++] = (byte) (end >> 8); + localContents[localContentsOffset++] = (byte) end; + int handlerPC = exceptionHandler.position; + localContents[localContentsOffset++] = (byte) (handlerPC >> 8); + localContents[localContentsOffset++] = (byte) handlerPC; + if (exceptionHandler.exceptionType == null) { + // any exception handler + localContentsOffset += 2; + } else { + int nameIndex; + if (exceptionHandler.exceptionType == TypeBinding.NullBinding) { + /* represents denote ClassNotFoundException, see class literal access*/ + nameIndex = constantPool.literalIndexForJavaLangClassNotFoundException(); + } else { + nameIndex = constantPool.literalIndex(exceptionHandler.exceptionType); + } + localContents[localContentsOffset++] = (byte) (nameIndex >> 8); + localContents[localContentsOffset++] = (byte) nameIndex; + } + } + // 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[] pcToSourceMapTable; + if (((pcToSourceMapTable = codeStream.pcToSourceMap) != null) + && (codeStream.pcToSourceMapSize != 0)) { + int lineNumberNameIndex = + constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName); + if (localContentsOffset + 8 >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8); + localContents[localContentsOffset++] = (byte) lineNumberNameIndex; + int lineNumberTableOffset = localContentsOffset; + localContentsOffset += 6; + // leave space for attribute_length and line_number_table_length + int numberOfEntries = 0; + int length = codeStream.pcToSourceMapSize; + for (int i = 0; i < length;) { + // write the entry + if (localContentsOffset + 4 >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + int pc = pcToSourceMapTable[i++]; + localContents[localContentsOffset++] = (byte) (pc >> 8); + localContents[localContentsOffset++] = (byte) pc; + int lineNumber = pcToSourceMapTable[i++]; + localContents[localContentsOffset++] = (byte) (lineNumber >> 8); + localContents[localContentsOffset++] = (byte) lineNumber; + numberOfEntries++; + } + // now we change the size of the line number attribute + int lineNumberAttr_length = numberOfEntries * 4 + 2; + localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24); + localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16); + localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8); + localContents[lineNumberTableOffset++] = (byte) lineNumberAttr_length; + localContents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8); + localContents[lineNumberTableOffset++] = (byte) numberOfEntries; + attributeNumber++; + } + } + // then we do the local variable attribute + if (codeStream.generateLocalVariableTableAttributes) { + int localVariableTableOffset = localContentsOffset; + int numberOfEntries = 0; + // codeAttribute.addLocalVariableTableAttribute(this); + if ((codeStream.pcToSourceMap != null) + && (codeStream.pcToSourceMapSize != 0)) { + int localVariableNameIndex = + constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName); + if (localContentsOffset + 8 >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8); + localContents[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++) { + LocalVariableBinding localVariable = codeStream.locals[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 + if (endPC == -1) { + localVariable.declaringScope.problemReporter().abortDueToInternalError( + Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$ + (AstNode) localVariable.declaringScope.methodScope().referenceContext); + } + if (localContentsOffset + 10 >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + // now we can safely add the local entry + numberOfEntries++; + localContents[localContentsOffset++] = (byte) (startPC >> 8); + localContents[localContentsOffset++] = (byte) startPC; + int length = endPC - startPC; + localContents[localContentsOffset++] = (byte) (length >> 8); + localContents[localContentsOffset++] = (byte) length; + nameIndex = constantPool.literalIndex(localVariable.name); + localContents[localContentsOffset++] = (byte) (nameIndex >> 8); + localContents[localContentsOffset++] = (byte) nameIndex; + descriptorIndex = constantPool.literalIndex(localVariable.type.signature()); + localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8); + localContents[localContentsOffset++] = (byte) descriptorIndex; + int resolvedPosition = localVariable.resolvedPosition; + localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8); + localContents[localContentsOffset++] = (byte) resolvedPosition; + } + } + } + int value = numberOfEntries * 10 + 2; + localVariableTableOffset += 2; + localContents[localVariableTableOffset++] = (byte) (value >> 24); + localContents[localVariableTableOffset++] = (byte) (value >> 16); + localContents[localVariableTableOffset++] = (byte) (value >> 8); + localContents[localVariableTableOffset++] = (byte) value; + localContents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8); + localContents[localVariableTableOffset] = (byte) numberOfEntries; + attributeNumber++; + } + } + // update the number of attributes + // ensure first that there is enough space available inside the contents array + if (codeAttributeAttributeOffset + 2 + >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8); + localContents[codeAttributeAttributeOffset] = (byte) attributeNumber; + // update the attribute length + int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6); + localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); + localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); + localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); + localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength; + contentsOffset = localContentsOffset; + } + + /** + * INTERNAL USE-ONLY + * That method completes the creation of the code attribute by setting + * - the attribute_length + * - max_stack + * - max_locals + * - code_length + * - exception table + * - and debug attributes if necessary. + * + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param codeAttributeOffset int + * @param exceptionHandler int[] + * @param startIndexes int[] + */ + public void completeCodeAttributeForClinit( + int codeAttributeOffset, + int[] exceptionHandler, + int[] startLineIndexes) { + // reinitialize the contents with the byte modified by the code stream + byte[] localContents = contents = codeStream.bCodeStream; + int localContentsOffset = codeStream.classFileOffset; + // codeAttributeOffset is the position inside contents 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 contentsLength; + int code_length = codeStream.position; + if (code_length > 65535) { + codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit( + codeStream.methodDeclaration.scope.referenceType()); + } + if (localContentsOffset + 20 >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + int max_stack = codeStream.stackMax; + localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); + localContents[codeAttributeOffset + 7] = (byte) max_stack; + int max_locals = codeStream.maxLocals; + localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); + localContents[codeAttributeOffset + 9] = (byte) max_locals; + localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24); + localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16); + localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8); + localContents[codeAttributeOffset + 13] = (byte) code_length; + + // write the exception table + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 1; + int start = exceptionHandler[0]; + localContents[localContentsOffset++] = (byte) (start >> 8); + localContents[localContentsOffset++] = (byte) start; + int end = exceptionHandler[1]; + localContents[localContentsOffset++] = (byte) (end >> 8); + localContents[localContentsOffset++] = (byte) end; + int handlerPC = exceptionHandler[2]; + localContents[localContentsOffset++] = (byte) (handlerPC >> 8); + localContents[localContentsOffset++] = (byte) handlerPC; + int nameIndex = constantPool.literalIndexForJavaLangException(); + localContents[localContentsOffset++] = (byte) (nameIndex >> 8); + localContents[localContentsOffset++] = (byte) nameIndex; + + // debug attributes + int codeAttributeAttributeOffset = localContentsOffset; + int attributeNumber = 0; // leave two bytes for the attribute_length + localContentsOffset += 2; // first we handle the linenumber attribute + + // 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); + localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8); + localContents[localContentsOffset++] = (byte) lineNumberNameIndex; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 6; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 1; + // first entry at pc = 0 + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = (byte) (problemLine >> 8); + localContents[localContentsOffset++] = (byte) problemLine; + // now we change the size of the line number attribute + attributeNumber++; + } + // then we do the local variable attribute + if (codeStream.generateLocalVariableTableAttributes) { + int localVariableNameIndex = + constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName); + if (localContentsOffset + 8 >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8); + localContents[localContentsOffset++] = (byte) localVariableNameIndex; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 2; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 0; + attributeNumber++; + } + // update the number of attributes + // ensure first that there is enough space available inside the contents array + if (codeAttributeAttributeOffset + 2 + >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8); + localContents[codeAttributeAttributeOffset] = (byte) attributeNumber; + // update the attribute length + int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6); + localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); + localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); + localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); + localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength; + contentsOffset = localContentsOffset; + } + + /** + * INTERNAL USE-ONLY + * That method completes the creation of the code attribute by setting + * - the attribute_length + * - max_stack + * - max_locals + * - code_length + * - exception table + * - and debug attributes if necessary. + * + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param codeAttributeOffset int + * @param exceptionHandler int[] + */ + public void completeCodeAttributeForProblemMethod( + AbstractMethodDeclaration method, + MethodBinding binding, + int codeAttributeOffset, + int[] exceptionHandler, + int[] startLineIndexes) { + // reinitialize the localContents with the byte modified by the code stream + byte[] localContents = 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; + localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); + localContents[codeAttributeOffset + 7] = (byte) max_stack; + int max_locals = codeStream.maxLocals; + localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); + localContents[codeAttributeOffset + 9] = (byte) max_locals; + int code_length = codeStream.position; + localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24); + localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16); + localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8); + localContents[codeAttributeOffset + 13] = (byte) code_length; + // write the exception table + int contentsLength; + if (localContentsOffset + 50 >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 1; + int start = exceptionHandler[0]; + localContents[localContentsOffset++] = (byte) (start >> 8); + localContents[localContentsOffset++] = (byte) start; + int end = exceptionHandler[1]; + localContents[localContentsOffset++] = (byte) (end >> 8); + localContents[localContentsOffset++] = (byte) end; + int handlerPC = exceptionHandler[2]; + localContents[localContentsOffset++] = (byte) (handlerPC >> 8); + localContents[localContentsOffset++] = (byte) handlerPC; + int nameIndex = constantPool.literalIndexForJavaLangException(); + localContents[localContentsOffset++] = (byte) (nameIndex >> 8); + localContents[localContentsOffset++] = (byte) nameIndex; // 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); + localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8); + localContents[localContentsOffset++] = (byte) lineNumberNameIndex; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 6; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 1; + if (problemLine == 0) { + problemLine = searchLineNumber(startLineIndexes, binding.sourceStart()); + } + // first entry at pc = 0 + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = (byte) (problemLine >> 8); + localContents[localContentsOffset++] = (byte) problemLine; + // now we change the size of the line number attribute + attributeNumber++; + } + // then we do the local variable attribute + if (codeStream.generateLocalVariableTableAttributes) { + // compute the resolved position for the arguments of the method + int argSize; + int localVariableTableOffset = localContentsOffset; + int numberOfEntries = 0; + // codeAttribute.addLocalVariableTableAttribute(this); + int localVariableNameIndex = + constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName); + if (localContentsOffset + 8 >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8); + localContents[localContentsOffset++] = (byte) localVariableNameIndex; + localContentsOffset += 6; + // leave space for attribute_length and local_variable_table_length + int descriptorIndex; + if (!codeStream.methodDeclaration.isStatic()) { + numberOfEntries++; + if (localContentsOffset + 10 >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = (byte) (code_length >> 8); + localContents[localContentsOffset++] = (byte) code_length; + nameIndex = constantPool.literalIndex(QualifiedNamesConstants.This); + localContents[localContentsOffset++] = (byte) (nameIndex >> 8); + localContents[localContentsOffset++] = (byte) nameIndex; + descriptorIndex = + constantPool.literalIndex( + codeStream.methodDeclaration.binding.declaringClass.signature()); + localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8); + localContents[localContentsOffset++] = (byte) descriptorIndex; + // the resolved position for this is always 0 + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 0; + } + if (binding.isConstructor()) { + ReferenceBinding declaringClass = binding.declaringClass; + if (declaringClass.isNestedType()) { + NestedTypeBinding methodDeclaringClass = (NestedTypeBinding) declaringClass; + argSize = methodDeclaringClass.syntheticArgumentsOffset; + SyntheticArgumentBinding[] syntheticArguments; + if ((syntheticArguments = methodDeclaringClass.syntheticEnclosingInstances()) + != null) { + for (int i = 0, max = syntheticArguments.length; i < max; i++) { + LocalVariableBinding localVariable = syntheticArguments[i]; + if (localContentsOffset + 10 >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + // now we can safely add the local entry + numberOfEntries++; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = (byte) (code_length >> 8); + localContents[localContentsOffset++] = (byte) code_length; + nameIndex = constantPool.literalIndex(localVariable.name); + localContents[localContentsOffset++] = (byte) (nameIndex >> 8); + localContents[localContentsOffset++] = (byte) nameIndex; + descriptorIndex = constantPool.literalIndex(localVariable.type.signature()); + localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8); + localContents[localContentsOffset++] = (byte) descriptorIndex; + int resolvedPosition = localVariable.resolvedPosition; + localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8); + localContents[localContentsOffset++] = (byte) resolvedPosition; + } + } + } else { + argSize = 1; + } + } else { + argSize = binding.isStatic() ? 0 : 1; + } + if (method.binding != null) { + TypeBinding[] parameters = method.binding.parameters; + Argument[] arguments = method.arguments; + if ((parameters != null) && (arguments != null)) { + for (int i = 0, max = parameters.length; i < max; i++) { + TypeBinding argumentBinding = parameters[i]; + if (localContentsOffset + 10 >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + // now we can safely add the local entry + numberOfEntries++; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = 0; + localContents[localContentsOffset++] = (byte) (code_length >> 8); + localContents[localContentsOffset++] = (byte) code_length; + nameIndex = constantPool.literalIndex(arguments[i].name); + localContents[localContentsOffset++] = (byte) (nameIndex >> 8); + localContents[localContentsOffset++] = (byte) nameIndex; + descriptorIndex = constantPool.literalIndex(argumentBinding.signature()); + localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8); + localContents[localContentsOffset++] = (byte) descriptorIndex; + int resolvedPosition = argSize; + if ((argumentBinding == TypeBinding.LongBinding) + || (argumentBinding == TypeBinding.DoubleBinding)) + argSize += 2; + else + argSize++; + localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8); + localContents[localContentsOffset++] = (byte) resolvedPosition; + } + } + } + int value = numberOfEntries * 10 + 2; + localVariableTableOffset += 2; + localContents[localVariableTableOffset++] = (byte) (value >> 24); + localContents[localVariableTableOffset++] = (byte) (value >> 16); + localContents[localVariableTableOffset++] = (byte) (value >> 8); + localContents[localVariableTableOffset++] = (byte) value; + localContents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8); + localContents[localVariableTableOffset] = (byte) numberOfEntries; + attributeNumber++; + } + // update the number of attributes// ensure first that there is enough space available inside the localContents array + if (codeAttributeAttributeOffset + 2 + >= (contentsLength = localContents.length)) { + System.arraycopy( + contents, + 0, + (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8); + localContents[codeAttributeAttributeOffset] = (byte) attributeNumber; + // update the attribute length + int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6); + localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); + localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); + localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); + localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength; + contentsOffset = localContentsOffset; + } + + /** + * INTERNAL USE-ONLY + * That method completes the creation of the code attribute by setting + * - the attribute_length + * - max_stack + * - max_locals + * - code_length + * - exception table + * - and debug attributes if necessary. + * + * @param binding org.eclipse.jdt.internal.compiler.lookup.SyntheticAccessMethodBinding + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param codeAttributeOffset int + */ + public void completeCodeAttributeForSyntheticAccessMethod( + SyntheticAccessMethodBinding binding, + int codeAttributeOffset, + int[] startLineIndexes) { + // reinitialize the contents with the byte modified by the code stream + contents = codeStream.bCodeStream; + int localContentsOffset = codeStream.classFileOffset; + // codeAttributeOffset is the position inside contents 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; + contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); + contents[codeAttributeOffset + 7] = (byte) max_stack; + int max_locals = codeStream.maxLocals; + contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); + contents[codeAttributeOffset + 9] = (byte) max_locals; + int code_length = codeStream.position; + contents[codeAttributeOffset + 10] = (byte) (code_length >> 24); + contents[codeAttributeOffset + 11] = (byte) (code_length >> 16); + contents[codeAttributeOffset + 12] = (byte) (code_length >> 8); + contents[codeAttributeOffset + 13] = (byte) code_length; + int contentsLength; + if ((localContentsOffset + 40) >= (contentsLength = contents.length)) { + System.arraycopy( + contents, + 0, + (contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + // there is no exception table, so we need to offset by 2 the current offset and move + // on the attribute generation + localContentsOffset += 2; + // 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) { + int index = 0; + int lineNumberNameIndex = + constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName); + contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8); + contents[localContentsOffset++] = (byte) lineNumberNameIndex; + int lineNumberTableOffset = localContentsOffset; + localContentsOffset += 6; + // leave space for attribute_length and line_number_table_length + // Seems like do would be better, but this preserves the existing behavior. + index = searchLineNumber(startLineIndexes, binding.sourceStart); + contents[localContentsOffset++] = 0; + contents[localContentsOffset++] = 0; + contents[localContentsOffset++] = (byte) (index >> 8); + contents[localContentsOffset++] = (byte) index; + // now we change the size of the line number attribute + contents[lineNumberTableOffset++] = 0; + contents[lineNumberTableOffset++] = 0; + contents[lineNumberTableOffset++] = 0; + contents[lineNumberTableOffset++] = 6; + contents[lineNumberTableOffset++] = 0; + contents[lineNumberTableOffset++] = 1; + attributeNumber++; + } + // then we do the local variable attribute + if (codeStream.generateLocalVariableTableAttributes) { + int localVariableTableOffset = localContentsOffset; + int numberOfEntries = 0; + int localVariableNameIndex = + constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName); + if (localContentsOffset + 8 > (contentsLength = contents.length)) { + System.arraycopy( + contents, + 0, + (contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8); + 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++) { + LocalVariableBinding localVariable = codeStream.locals[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 + if (endPC == -1) { + localVariable.declaringScope.problemReporter().abortDueToInternalError( + Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$ + (AstNode) localVariable.declaringScope.methodScope().referenceContext); + } + if (localContentsOffset + 10 > (contentsLength = contents.length)) { + System.arraycopy( + contents, + 0, + (contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + // now we can safely add the local entry + numberOfEntries++; + 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.signature()); + contents[localContentsOffset++] = (byte) (descriptorIndex >> 8); + contents[localContentsOffset++] = (byte) descriptorIndex; + int resolvedPosition = localVariable.resolvedPosition; + contents[localContentsOffset++] = (byte) (resolvedPosition >> 8); + contents[localContentsOffset++] = (byte) resolvedPosition; + } + } + } + int value = numberOfEntries * 10 + 2; + localVariableTableOffset += 2; + contents[localVariableTableOffset++] = (byte) (value >> 24); + contents[localVariableTableOffset++] = (byte) (value >> 16); + contents[localVariableTableOffset++] = (byte) (value >> 8); + contents[localVariableTableOffset++] = (byte) value; + contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8); + contents[localVariableTableOffset] = (byte) numberOfEntries; + attributeNumber++; + } + // update the number of attributes + // ensure first that there is enough space available inside the contents array + if (codeAttributeAttributeOffset + 2 >= (contentsLength = contents.length)) { + System.arraycopy( + contents, + 0, + (contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8); + contents[codeAttributeAttributeOffset] = (byte) attributeNumber; + + // update the attribute length + int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6); + contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); + contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); + contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); + contents[codeAttributeOffset + 5] = (byte) codeAttributeLength; + contentsOffset = localContentsOffset; + } + + /** + * INTERNAL USE-ONLY + * Complete the creation of a method info by setting up the number of attributes at the right offset. + * + * @param methodAttributeOffset int + * @param attributeNumber int + */ + public void completeMethodInfo( + int methodAttributeOffset, + int attributeNumber) { + // update the number of attributes + contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); + contents[methodAttributeOffset] = (byte) attributeNumber; + } + + /* + * INTERNAL USE-ONLY + * Innerclasses get their name computed as they are generated, since some may not + * be actually outputed if sitting inside unreachable code. + * + * @param localType org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding + */ + public char[] computeConstantPoolName(LocalTypeBinding localType) { + if (localType.constantPoolName() != null) { + return localType.constantPoolName(); + } + // delegates to the outermost enclosing classfile, since it is the only one with a global vision of its innertypes. + if (enclosingClassFile != null) { + return this.outerMostEnclosingClassFile().computeConstantPoolName(localType); + } + if (nameUsage == null) + nameUsage = new HashtableOfType(); + + // ensure there is not already such a local type name defined by the user + int index = 0; + char[] candidateName; + while(true) { + if (localType.isMemberType()){ + if (index == 0){ + candidateName = CharOperation.concat( + localType.enclosingType().constantPoolName(), + localType.sourceName, + '$'); + } else { + // in case of collision, then member name gets extra $1 inserted + // e.g. class X { { class L{} new X(){ class L{} } } } + candidateName = CharOperation.concat( + localType.enclosingType().constantPoolName(), + '$', + String.valueOf(index).toCharArray(), + '$', + localType.sourceName); + } + } else if (localType.isAnonymousType()){ + candidateName = CharOperation.concat( + referenceBinding.constantPoolName(), + String.valueOf(index+1).toCharArray(), + '$'); + } else { + candidateName = CharOperation.concat( + referenceBinding.constantPoolName(), + '$', + String.valueOf(index+1).toCharArray(), + '$', + localType.sourceName); + } + if (nameUsage.get(candidateName) != null) { + index ++; + } else { + nameUsage.put(candidateName, localType); + break; + } + } + return candidateName; + } + + /** + * 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); + + // 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], false, null, null, 0); + } + } + 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.getProblems(); + 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 + * This methods returns a char[] representing the file name of the receiver + * + * @return char[] + */ + public char[] fileName() { + return constantPool.UTF8Cache.returnKeyFor(1); + } + + /** + * INTERNAL USE-ONLY + * That method generates the header of a code attribute. + * - the index inside the constant pool for the attribute name (i.e. Code) + * - leave some space for attribute_length(4), max_stack(2), max_locals(2), code_length(4). + */ + public void generateCodeAttributeHeader() { + int contentsLength; + if (contentsOffset + 20 >= (contentsLength = contents.length)) { + System.arraycopy( + contents, + 0, + (contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + int constantValueNameIndex = + constantPool.literalIndex(AttributeNamesConstants.CodeName); + contents[contentsOffset++] = (byte) (constantValueNameIndex >> 8); + contents[contentsOffset++] = (byte) constantValueNameIndex; + // leave space for attribute_length(4), max_stack(2), max_locals(2), code_length(4) + contentsOffset += 12; + } + + /** + * INTERNAL USE-ONLY + * That method generates the attributes of a code attribute. + * They could be: + * - an exception attribute for each try/catch found inside the method + * - a deprecated attribute + * - a synthetic attribute for synthetic access methods + * + * It returns the number of attributes created for the code attribute. + * + * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding + * @return int + */ + public int generateMethodInfoAttribute(MethodBinding methodBinding) { + // leave two bytes for the attribute_number + contentsOffset += 2; + // now we can handle all the attribute for that method info: + // it could be: + // - a CodeAttribute + // - a ExceptionAttribute + // - a DeprecatedAttribute + // - a SyntheticAttribute + + // Exception attribute + ReferenceBinding[] thrownsExceptions; + int contentsLength; + int attributeNumber = 0; + if ((thrownsExceptions = methodBinding.thrownExceptions) != NoExceptions) { + // The method has a throw clause. So we need to add an exception attribute + // check that there is enough space to write all the bytes for the exception attribute + int length = thrownsExceptions.length; + if (contentsOffset + (8 + length * 2) >= (contentsLength = contents.length)) { + System.arraycopy( + contents, + 0, + (contents = + new byte[contentsLength + Math.max(INCREMENT_SIZE, (8 + length * 2))]), + 0, + contentsLength); + } + int exceptionNameIndex = + constantPool.literalIndex(AttributeNamesConstants.ExceptionsName); + contents[contentsOffset++] = (byte) (exceptionNameIndex >> 8); + contents[contentsOffset++] = (byte) exceptionNameIndex; + // The attribute length = length * 2 + 2 in case of a exception attribute + int attributeLength = length * 2 + 2; + contents[contentsOffset++] = (byte) (attributeLength >> 24); + contents[contentsOffset++] = (byte) (attributeLength >> 16); + contents[contentsOffset++] = (byte) (attributeLength >> 8); + contents[contentsOffset++] = (byte) attributeLength; + contents[contentsOffset++] = (byte) (length >> 8); + contents[contentsOffset++] = (byte) length; + for (int i = 0; i < length; i++) { + int exceptionIndex = constantPool.literalIndex(thrownsExceptions[i]); + contents[contentsOffset++] = (byte) (exceptionIndex >> 8); + contents[contentsOffset++] = (byte) exceptionIndex; + } + attributeNumber++; + } + // Deprecated attribute + // Check that there is enough space to write the deprecated attribute + if (contentsOffset + 6 >= (contentsLength = contents.length)) { + System.arraycopy( + contents, + 0, + (contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + if (methodBinding.isDeprecated()) { + int deprecatedAttributeNameIndex = + constantPool.literalIndex(AttributeNamesConstants.DeprecatedName); + contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8); + contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex; + // the length of a deprecated attribute is equals to 0 + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + + attributeNumber++; + } + // Synthetic attribute + // Check that there is enough space to write the deprecated attribute + if (contentsOffset + 6 >= (contentsLength = contents.length)) { + System.arraycopy( + contents, + 0, + (contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + if (methodBinding.isSynthetic()) { + 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; + + attributeNumber++; + } + return attributeNumber; + } + + /** + * INTERNAL USE-ONLY + * That method generates the header of a method info: + * The header consists in: + * - the access flags + * - the name index of the method name inside the constant pool + * - the descriptor index of the signature of the method inside the constant pool. + * + * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding + */ + public void generateMethodInfoHeader(MethodBinding methodBinding) { + // check that there is enough space to write all the bytes for the method info corresponding + // to the @methodBinding + int contentsLength; + methodCount++; // add one more method + if (contentsOffset + 10 >= (contentsLength = contents.length)) { + System.arraycopy( + contents, + 0, + (contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + int accessFlags = methodBinding.getAccessFlags(); + if (methodBinding.isRequiredToClearPrivateModifier()) { + accessFlags &= ~AccPrivate; + } + contents[contentsOffset++] = (byte) (accessFlags >> 8); + contents[contentsOffset++] = (byte) accessFlags; + int nameIndex = constantPool.literalIndex(methodBinding.selector); + contents[contentsOffset++] = (byte) (nameIndex >> 8); + contents[contentsOffset++] = (byte) nameIndex; + int descriptorIndex = constantPool.literalIndex(methodBinding.signature()); + contents[contentsOffset++] = (byte) (descriptorIndex >> 8); + contents[contentsOffset++] = (byte) descriptorIndex; + } + + /** + * INTERNAL USE-ONLY + * That method generates the method info header of a clinit: + * The header consists in: + * - the access flags (always default access + static) + * - the name index of the method name (always ) inside the constant pool + * - the descriptor index of the signature (always ()V) of the method inside the constant pool. + * + * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding + */ + public void generateMethodInfoHeaderForClinit() { + // check that there is enough space to write all the bytes for the method info corresponding + // to the @methodBinding + int contentsLength; + methodCount++; // add one more method + if (contentsOffset + 10 >= (contentsLength = contents.length)) { + System.arraycopy( + contents, + 0, + (contents = new byte[contentsLength + INCREMENT_SIZE]), + 0, + contentsLength); + } + contents[contentsOffset++] = (byte) ((AccDefault | AccStatic) >> 8); + contents[contentsOffset++] = (byte) (AccDefault | AccStatic); + int nameIndex = constantPool.literalIndex(QualifiedNamesConstants.Clinit); + contents[contentsOffset++] = (byte) (nameIndex >> 8); + contents[contentsOffset++] = (byte) nameIndex; + int descriptorIndex = + constantPool.literalIndex(QualifiedNamesConstants.ClinitSignature); + contents[contentsOffset++] = (byte) (descriptorIndex >> 8); + contents[contentsOffset++] = (byte) descriptorIndex; + // We know that we won't get more than 1 attribute: the code attribute + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 1; + } + + /** + * EXTERNAL API + * Answer the actual bytes of the class file + * + * This method encodes the receiver structure into a byte array which is the content of the classfile. + * Returns the byte array that represents the encoded structure of the receiver. + * + * @return byte[] + */ + public byte[] getBytes() { + byte[] fullContents = new byte[headerOffset + contentsOffset]; + System.arraycopy(header, 0, fullContents, 0, headerOffset); + System.arraycopy(contents, 0, fullContents, headerOffset, contentsOffset); + return fullContents; + } + + /** + * EXTERNAL API + * Answer the compound name of the class file. + * @return char[][] + * e.g. {{java}, {util}, {Hashtable}}. + */ + public char[][] getCompoundName() { + return CharOperation.splitOn('/', fileName()); + } + + /** + * INTERNAL USE-ONLY + * Returns the most enclosing classfile of the receiver. This is used know to store the constant pool name + * for all inner types of the receiver. + * @return org.eclipse.jdt.internal.compiler.codegen.ClassFile + */ + public ClassFile outerMostEnclosingClassFile() { + ClassFile current = this; + while (current.enclosingClassFile != null) + current = current.enclosingClassFile; + return current; + } + + /** + * INTERNAL USE-ONLY + * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the + * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications. + * + * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding + */ + public void recordEnclosingTypeAttributes(ReferenceBinding binding) { + // add all the enclosing types + ReferenceBinding enclosingType = referenceBinding.enclosingType(); + int depth = 0; + while (enclosingType != null) { + depth++; + enclosingType = enclosingType.enclosingType(); + } + enclosingType = referenceBinding; + ReferenceBinding enclosingTypes[]; + if (depth >= 2) { + enclosingTypes = new ReferenceBinding[depth]; + for (int i = depth - 1; i >= 0; i--) { + enclosingTypes[i] = enclosingType; + enclosingType = enclosingType.enclosingType(); + } + for (int i = 0; i < depth; i++) { + addInnerClasses(enclosingTypes[i]); + } + } else { + addInnerClasses(referenceBinding); + } + } + + /** + * INTERNAL USE-ONLY + * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the + * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications. + * + * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding + */ + public void recordNestedLocalAttribute(ReferenceBinding binding) { + // add all the enclosing types + ReferenceBinding enclosingType = referenceBinding.enclosingType(); + int depth = 0; + while (enclosingType != null) { + depth++; + enclosingType = enclosingType.enclosingType(); + } + enclosingType = referenceBinding; + ReferenceBinding enclosingTypes[]; + if (depth >= 2) { + enclosingTypes = new ReferenceBinding[depth]; + for (int i = depth - 1; i >= 0; i--) { + enclosingTypes[i] = enclosingType; + enclosingType = enclosingType.enclosingType(); + } + for (int i = 0; i < depth; i++) + addInnerClasses(enclosingTypes[i]); + } else { + addInnerClasses(binding); + } + } + + /** + * INTERNAL USE-ONLY + * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the + * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications. + * + * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding + */ + public void recordNestedMemberAttribute(ReferenceBinding binding) { + addInnerClasses(binding); + } + + /** + * INTERNAL USE-ONLY + * Search the line number corresponding to a specific position + * + * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding + */ + 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() { + // leave some space for the methodCount + 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(); + } + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/CompilationResult.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/CompilationResult.java new file mode 100644 index 0000000..6974459 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/CompilationResult.java @@ -0,0 +1,292 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler; + +/** + * A compilation result consists of all information returned by the compiler for + * a single compiled compilation source unit. This includes: + * + * + * The principle structure and binary may be null if the compiler could not produce them. + * If neither could be produced, there is no corresponding entry for the type. + * + * The dependency info includes type references such as supertypes, field types, method + * parameter and return types, local variable types, types of intermediate expressions, etc. + * It also includes the namespaces (packages) in which names were looked up. + * It does not include finer grained dependencies such as information about + * specific fields and methods which were referenced, but does contain their + * declaring types and any other types used to locate such fields or methods. + */ + +import net.sourceforge.phpdt.core.compiler.*; +import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.env.*; +import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext; + +import java.util.*; + +public class CompilationResult { + + public IProblem problems[]; + public int problemCount; + public ICompilationUnit compilationUnit; + private Map problemsMap; + private Map firstErrorsMap; + private HashSet duplicateProblems; + private int maxProblemPerUnit; + public char[][][] qualifiedReferences; + public char[][] simpleNameReferences; + + public int lineSeparatorPositions[]; + public Hashtable compiledTypes = new Hashtable(11); + public int unitIndex, totalUnitsKnown; + public boolean hasBeenAccepted = false; + public char[] fileName; + +public CompilationResult( + char[] fileName, + int unitIndex, + int totalUnitsKnown, + int maxProblemPerUnit){ + + this.fileName = fileName; + this.unitIndex = unitIndex; + this.totalUnitsKnown = totalUnitsKnown; + this.maxProblemPerUnit = maxProblemPerUnit; + +} + +public CompilationResult( + ICompilationUnit compilationUnit, + int unitIndex, + int totalUnitsKnown, + int maxProblemPerUnit){ + + this.fileName = compilationUnit.getFileName(); + this.compilationUnit = compilationUnit; + this.unitIndex = unitIndex; + this.totalUnitsKnown = totalUnitsKnown; + this.maxProblemPerUnit = maxProblemPerUnit; + +} +private int computePriority(IProblem problem){ + + final int P_STATIC = 1000; + final int P_OUTSIDE_METHOD = 4000; + final int P_FIRST_ERROR = 2000; + final int P_ERROR = 10000; + + int priority = 1000 - problem.getSourceLineNumber(); // early problems first + if (priority < 0) priority = 0; + if (problem.isError()){ + priority += P_ERROR; + } + ReferenceContext context = problemsMap == null ? null : (ReferenceContext) problemsMap.get(problem); + if (context != null){ + if (context instanceof AbstractMethodDeclaration){ + AbstractMethodDeclaration method = (AbstractMethodDeclaration) context; + if (method.isStatic()) { + priority += P_STATIC; + } + } else { + priority += P_OUTSIDE_METHOD; + } + } else { + priority += P_OUTSIDE_METHOD; + } + if (firstErrorsMap.containsKey(problem)){ + priority += P_FIRST_ERROR; + } + return priority; +} +public ClassFile[] getClassFiles() { + Enumeration enum = compiledTypes.elements(); + ClassFile[] classFiles = new ClassFile[compiledTypes.size()]; + int index = 0; + while (enum.hasMoreElements()){ + classFiles[index++] = (ClassFile)enum.nextElement(); + } + return classFiles; +} +/** + * Answer the initial compilation unit corresponding to the present compilation result + */ +public ICompilationUnit getCompilationUnit(){ + return compilationUnit; +} +/** + * Answer the initial file name + */ +public char[] getFileName(){ + return fileName; +} +/** + * Answer the problems (errors and warnings) encountered during compilation. + * + * This is not a compiler internal API - it has side-effects ! + * It is intended to be used only once all problems have been detected, + * and makes sure the problems slot as the exact size of the number of + * problems. + */ +public IProblem[] getProblems() { + + // Re-adjust the size of the problems if necessary. + if (problems != null) { + + if (this.problemCount != problems.length) { + System.arraycopy(problems, 0, (problems = new IProblem[problemCount]), 0, problemCount); + } + + if (this.maxProblemPerUnit > 0 && this.problemCount > this.maxProblemPerUnit){ + quickPrioritize(problems, 0, problemCount - 1); + this.problemCount = this.maxProblemPerUnit; + System.arraycopy(problems, 0, (problems = new IProblem[problemCount]), 0, problemCount); + } + + // Sort problems per source positions. + quicksort(problems, 0, problems.length-1); + } + return problems; +} + +public boolean hasErrors() { + if (problems != null) + for (int i = 0; i < problemCount; i++) { + if (problems[i].isError()) + return true; + } + return false; +} +public boolean hasProblems() { + return problemCount != 0; +} +public boolean hasWarnings() { + if (problems != null) + for (int i = 0; i < problemCount; i++) { + if (problems[i].isWarning()) + return true; + } + return false; +} + +private static void quicksort(IProblem arr[], int left, int right) { + int i, last, pos; + + if (left >= right) { + /* do nothing if array contains fewer than two */ + return; + /* two elements */ + } + + swap(arr, left, (left + right) / 2); + last = left; + pos = arr[left].getSourceStart(); + + for (i = left + 1; i <= right; i++) { + if (arr[i].getSourceStart() < pos) { + swap(arr, ++last, i); + } + } + + swap(arr, left, last); + quicksort(arr, left, last - 1); + quicksort(arr, last + 1, right); +} + +private void quickPrioritize(IProblem arr[], int left, int right) { + int i, last, prio; + + if (left >= right) { + /* do nothing if array contains fewer than two */ + return; + /* two elements */ + } + + swap(arr, left, (left + right) / 2); + last = left; + prio = computePriority(arr[left]); + + for (i = left + 1; i <= right; i++) { + if (computePriority(arr[i]) > prio) { + swap(arr, ++last, i); + } + } + + swap(arr, left, last); + quickPrioritize(arr, left, last - 1); + quickPrioritize(arr, last + 1, right); +} + +/** + * For now, remember the compiled type using its compound name. + */ +public void record(char[] typeName, ClassFile classFile) { + compiledTypes.put(typeName, classFile); +} +public void record(IProblem newProblem, ReferenceContext referenceContext) { + if (problemCount == 0) { + problems = new IProblem[5]; + } else { + if (problemCount == problems.length) + System.arraycopy(problems, 0, (problems = new IProblem[problemCount * 2]), 0, problemCount); + }; + problems[problemCount++] = newProblem; + if (referenceContext != null){ + if (problemsMap == null) problemsMap = new Hashtable(5); + if (firstErrorsMap == null) firstErrorsMap = new Hashtable(5); + if (newProblem.isError() && !referenceContext.hasErrors()) firstErrorsMap.put(newProblem, newProblem); + problemsMap.put(newProblem, referenceContext); + } +} +private static void swap(IProblem arr[], int i, int j) { + IProblem tmp; + tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; +} +CompilationResult tagAsAccepted(){ + this.hasBeenAccepted = true; + this.problemsMap = null; // flush + return this; +} + +public String toString(){ + StringBuffer buffer = new StringBuffer(); + if (this.fileName != null){ + buffer.append("Filename : ").append(this.fileName).append('\n'); //$NON-NLS-1$ + } + if (this.compiledTypes != null){ + buffer.append("COMPILED type(s) \n"); //$NON-NLS-1$ + Enumeration typeNames = this.compiledTypes.keys(); + while (typeNames.hasMoreElements()) { + char[] typeName = (char[]) typeNames.nextElement(); + buffer.append("\t - ").append(typeName).append('\n'); //$NON-NLS-1$ + + } + } else { + buffer.append("No COMPILED type\n"); //$NON-NLS-1$ + } + if (problems != null){ + buffer.append(this.problemCount).append(" PROBLEM(s) detected \n"); //$NON-NLS-1$//$NON-NLS-2$ + for (int i = 0; i < this.problemCount; i++){ + buffer.append("\t - ").append(this.problems[i]).append('\n'); //$NON-NLS-1$ + } + } else { + buffer.append("No PROBLEM\n"); //$NON-NLS-1$ + } + return buffer.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/Compiler.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/Compiler.java new file mode 100644 index 0000000..e0377d7 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/Compiler.java @@ -0,0 +1,595 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler; + +import net.sourceforge.phpdt.core.compiler.*; +import net.sourceforge.phpdt.internal.compiler.env.*; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.parser.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; +import net.sourceforge.phpdt.internal.compiler.util.*; + +import java.io.*; +import java.util.*; + +public class Compiler implements ITypeRequestor, ProblemSeverities { + public Parser parser; + ICompilerRequestor requestor; + public CompilerOptions options; + public ProblemReporter problemReporter; + + // management of unit to be processed + //public CompilationUnitResult currentCompilationUnitResult; + CompilationUnitDeclaration[] unitsToProcess; + int totalUnits; // (totalUnits-1) gives the last unit in unitToProcess + + // name lookup + public LookupEnvironment lookupEnvironment; + + // ONCE STABILIZED, THESE SHOULD RETURN TO A FINAL FIELD + public static boolean DEBUG = false; + public int parseThreshold = -1; + // number of initial units parsed at once (-1: none) + + /* + * Static requestor reserved to listening compilation results in debug mode, + * so as for example to monitor compiler activity independantly from a particular + * builder implementation. It is reset at the end of compilation, and should not + * persist any information after having been reset. + */ + public static IDebugRequestor DebugRequestor = null; + + /** + * Answer a new compiler using the given name environment and compiler options. + * The environment and options will be in effect for the lifetime of the compiler. + * When the compiler is run, compilation results are sent to the given requestor. + * + * @param environment org.eclipse.jdt.internal.compiler.api.env.INameEnvironment + * Environment used by the compiler in order to resolve type and package + * names. The name environment implements the actual connection of the compiler + * to the outside world (e.g. in batch mode the name environment is performing + * pure file accesses, reuse previous build state or connection to repositories). + * Note: the name environment is responsible for implementing the actual classpath + * rules. + * + * @param policy org.eclipse.jdt.internal.compiler.api.problem.IErrorHandlingPolicy + * Configurable part for problem handling, allowing the compiler client to + * specify the rules for handling problems (stop on first error or accumulate + * them all) and at the same time perform some actions such as opening a dialog + * in UI when compiling interactively. + * @see org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies + * + * @param requestor org.eclipse.jdt.internal.compiler.api.ICompilerRequestor + * Component which will receive and persist all compilation results and is intended + * to consume them as they are produced. Typically, in a batch compiler, it is + * responsible for writing out the actual .class files to the file system. + * @see org.eclipse.jdt.internal.compiler.CompilationResult + * + * @param problemFactory org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory + * Factory used inside the compiler to create problem descriptors. It allows the + * compiler client to supply its own representation of compilation problems in + * order to avoid object conversions. Note that the factory is not supposed + * to accumulate the created problems, the compiler will gather them all and hand + * them back as part of the compilation unit result. + */ + public Compiler( + INameEnvironment environment, + IErrorHandlingPolicy policy, + Map settings, + final ICompilerRequestor requestor, + IProblemFactory problemFactory) { + + // create a problem handler given a handling policy + this.options = new CompilerOptions(settings); + + // wrap requestor in DebugRequestor if one is specified + if(DebugRequestor == null) { + this.requestor = requestor; + } else { + this.requestor = new ICompilerRequestor(){ + public void acceptResult(CompilationResult result){ + if (DebugRequestor.isActive()){ + DebugRequestor.acceptDebugResult(result); + } + requestor.acceptResult(result); + } + }; + } + this.problemReporter = + new ProblemReporter(policy, this.options, problemFactory); + this.lookupEnvironment = + new LookupEnvironment(this, options, problemReporter, environment); + this.parser = + new Parser( + problemReporter, + this.options.parseLiteralExpressionsAsConstants, + this.options.assertMode); + } + + /** + * Answer a new compiler using the given name environment and compiler options. + * The environment and options will be in effect for the lifetime of the compiler. + * When the compiler is run, compilation results are sent to the given requestor. + * + * @param environment org.eclipse.jdt.internal.compiler.api.env.INameEnvironment + * Environment used by the compiler in order to resolve type and package + * names. The name environment implements the actual connection of the compiler + * to the outside world (e.g. in batch mode the name environment is performing + * pure file accesses, reuse previous build state or connection to repositories). + * Note: the name environment is responsible for implementing the actual classpath + * rules. + * + * @param policy org.eclipse.jdt.internal.compiler.api.problem.IErrorHandlingPolicy + * Configurable part for problem handling, allowing the compiler client to + * specify the rules for handling problems (stop on first error or accumulate + * them all) and at the same time perform some actions such as opening a dialog + * in UI when compiling interactively. + * @see org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies + * + * @param requestor org.eclipse.jdt.internal.compiler.api.ICompilerRequestor + * Component which will receive and persist all compilation results and is intended + * to consume them as they are produced. Typically, in a batch compiler, it is + * responsible for writing out the actual .class files to the file system. + * @see org.eclipse.jdt.internal.compiler.CompilationResult + * + * @param problemFactory org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory + * Factory used inside the compiler to create problem descriptors. It allows the + * compiler client to supply its own representation of compilation problems in + * order to avoid object conversions. Note that the factory is not supposed + * to accumulate the created problems, the compiler will gather them all and hand + * them back as part of the compilation unit result. + * @param parseLiteralExpressionsAsConstants boolean + * This parameter is used to optimize the literals or leave them as they are in the source. + * If you put true, "Hello" + " world" will be converted to "Hello world". + */ + public Compiler( + INameEnvironment environment, + IErrorHandlingPolicy policy, + Map settings, + final ICompilerRequestor requestor, + IProblemFactory problemFactory, + boolean parseLiteralExpressionsAsConstants) { + + // create a problem handler given a handling policy + this.options = new CompilerOptions(settings); + + // wrap requestor in DebugRequestor if one is specified + if(DebugRequestor == null) { + this.requestor = requestor; + } else { + this.requestor = new ICompilerRequestor(){ + public void acceptResult(CompilationResult result){ + if (DebugRequestor.isActive()){ + DebugRequestor.acceptDebugResult(result); + } + requestor.acceptResult(result); + } + }; + } + this.problemReporter = + new ProblemReporter(policy, this.options, problemFactory); + this.lookupEnvironment = + new LookupEnvironment(this, options, problemReporter, environment); + this.parser = + new Parser( + problemReporter, + parseLiteralExpressionsAsConstants, + this.options.assertMode); + } + + /** + * Add an additional binary type + */ + public void accept(IBinaryType binaryType, PackageBinding packageBinding) { + lookupEnvironment.createBinaryTypeFrom(binaryType, packageBinding); + } + + /** + * Add an additional compilation unit into the loop + * -> build compilation unit declarations, their bindings and record their results. + */ + public void accept(ICompilationUnit sourceUnit) { + // Switch the current policy and compilation result for this unit to the requested one. + CompilationResult unitResult = + new CompilationResult(sourceUnit, totalUnits, totalUnits, this.options.maxProblemsPerUnit); + try { + // diet parsing for large collection of unit + CompilationUnitDeclaration parsedUnit; + if (totalUnits < parseThreshold) { + parsedUnit = parser.parse(sourceUnit, unitResult); + } else { + parsedUnit = parser.dietParse(sourceUnit, unitResult); + } + + if (options.verbose) { + System.out.println( + Util.bind( + "compilation.request" , //$NON-NLS-1$ + new String[] { + String.valueOf(totalUnits + 1), + String.valueOf(totalUnits + 1), + new String(sourceUnit.getFileName())})); + } + + // initial type binding creation + lookupEnvironment.buildTypeBindings(parsedUnit); + this.addCompilationUnit(sourceUnit, parsedUnit); + + // binding resolution + lookupEnvironment.completeTypeBindings(parsedUnit); + } catch (AbortCompilationUnit e) { + // at this point, currentCompilationUnitResult may not be sourceUnit, but some other + // one requested further along to resolve sourceUnit. + if (unitResult.compilationUnit == sourceUnit) { // only report once + requestor.acceptResult(unitResult.tagAsAccepted()); + } else { + throw e; // want to abort enclosing request to compile + } + } + } + + /** + * Add additional source types + */ + public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding) { + problemReporter.abortDueToInternalError( + Util.bind( + "abort.againstSourceModel " , //$NON-NLS-1$ + String.valueOf(sourceTypes[0].getName()), + String.valueOf(sourceTypes[0].getFileName()))); + } + + protected void addCompilationUnit( + ICompilationUnit sourceUnit, + CompilationUnitDeclaration parsedUnit) { + + // append the unit to the list of ones to process later on + int size = unitsToProcess.length; + if (totalUnits == size) + // when growing reposition units starting at position 0 + System.arraycopy( + unitsToProcess, + 0, + (unitsToProcess = new CompilationUnitDeclaration[size * 2]), + 0, + totalUnits); + unitsToProcess[totalUnits++] = parsedUnit; + } + + /** + * Add the initial set of compilation units into the loop + * -> build compilation unit declarations, their bindings and record their results. + */ + protected void beginToCompile(ICompilationUnit[] sourceUnits) { + int maxUnits = sourceUnits.length; + totalUnits = 0; + unitsToProcess = new CompilationUnitDeclaration[maxUnits]; + + // Switch the current policy and compilation result for this unit to the requested one. + for (int i = 0; i < maxUnits; i++) { + CompilationUnitDeclaration parsedUnit; + CompilationResult unitResult = + new CompilationResult(sourceUnits[i], i, maxUnits, this.options.maxProblemsPerUnit); + try { + // diet parsing for large collection of units + if (totalUnits < parseThreshold) { + parsedUnit = parser.parse(sourceUnits[i], unitResult); + } else { + parsedUnit = parser.dietParse(sourceUnits[i], unitResult); + } + if (options.verbose) { + System.out.println( + Util.bind( + "compilation.request" , //$NON-NLS-1$ + new String[] { + String.valueOf(i + 1), + String.valueOf(maxUnits), + new String(sourceUnits[i].getFileName())})); + } + // initial type binding creation + lookupEnvironment.buildTypeBindings(parsedUnit); + this.addCompilationUnit(sourceUnits[i], parsedUnit); + //} catch (AbortCompilationUnit e) { + // requestor.acceptResult(unitResult.tagAsAccepted()); + } finally { + sourceUnits[i] = null; // no longer hold onto the unit + } + } + // binding resolution + lookupEnvironment.completeTypeBindings(); + } + + /** + * General API + * -> compile each of supplied files + * -> recompile any required types for which we have an incomplete principle structure + */ + public void compile(ICompilationUnit[] sourceUnits) { + CompilationUnitDeclaration unit = null; + int i = 0; + try { + // build and record parsed units + + beginToCompile(sourceUnits); + + // process all units (some more could be injected in the loop by the lookup environment) + for (; i < totalUnits; i++) { + unit = unitsToProcess[i]; + try { + if (options.verbose) + System.out.println( + Util.bind( + "compilation.process" , //$NON-NLS-1$ + new String[] { + String.valueOf(i + 1), + String.valueOf(totalUnits), + new String(unitsToProcess[i].getFileName())})); + process(unit, i); + } finally { + // cleanup compilation unit result + unit.cleanUp(); + if (options.verbose) + System.out.println(Util.bind("compilation.done", //$NON-NLS-1$ + new String[] { + String.valueOf(i + 1), + String.valueOf(totalUnits), + new String(unitsToProcess[i].getFileName())})); + } + unitsToProcess[i] = null; // release reference to processed unit declaration + requestor.acceptResult(unit.compilationResult.tagAsAccepted()); + } + } catch (AbortCompilation e) { + this.handleInternalException(e, unit); + } catch (Error e) { + this.handleInternalException(e, unit, null); + throw e; // rethrow + } catch (RuntimeException e) { + this.handleInternalException(e, unit, null); + throw e; // rethrow + } finally { + this.reset(); + } + if (options.verbose) { + if (totalUnits > 1) { + System.out.println( + Util.bind("compilation.units" , String.valueOf(totalUnits))); //$NON-NLS-1$ + } else { + System.out.println( + Util.bind("compilation.unit" , String.valueOf(totalUnits))); //$NON-NLS-1$ + } + } + } + + protected void getMethodBodies(CompilationUnitDeclaration unit, int place) { + //fill the methods bodies in order for the code to be generated + + if (unit.ignoreMethodBodies) { + unit.ignoreFurtherInvestigation = true; + return; + // if initial diet parse did not work, no need to dig into method bodies. + } + + if (place < parseThreshold) + return; //work already done ... + + //real parse of the method.... + parser.scanner.setSource( + unit.compilationResult.compilationUnit.getContents()); + if (unit.types != null) { + for (int i = unit.types.length; --i >= 0;) + unit.types[i].parseMethod(parser, unit); + } + } + + /* + * Compiler crash recovery in case of unexpected runtime exceptions + */ + protected void handleInternalException( + Throwable internalException, + CompilationUnitDeclaration unit, + CompilationResult result) { + + /* dump a stack trace to the console */ + internalException.printStackTrace(); + + /* find a compilation result */ + if ((unit != null)) // basing result upon the current unit if available + result = unit.compilationResult; // current unit being processed ? + if ((result == null) && (unitsToProcess != null) && (totalUnits > 0)) + result = unitsToProcess[totalUnits - 1].compilationResult; + // last unit in beginToCompile ? + + if (result != null) { + /* create and record a compilation problem */ + StringWriter stringWriter = new StringWriter(); + PrintWriter writer = new PrintWriter(stringWriter); + internalException.printStackTrace(writer); + StringBuffer buffer = stringWriter.getBuffer(); + + result + .record( + problemReporter + .createProblem( + result.getFileName(), + IProblem.Unclassified, + new String[] { + Util.bind("compilation.internalError" ) //$NON-NLS-1$ + + "\n" //$NON-NLS-1$ + + buffer.toString()}, + Error, // severity + 0, // source start + 0, // source end + 0, // line number + unit, + result), + unit); + + /* hand back the compilation result */ + if (!result.hasBeenAccepted) { + requestor.acceptResult(result.tagAsAccepted()); + } + } + } + + /* + * Compiler recovery in case of internal AbortCompilation event + */ + protected void handleInternalException( + AbortCompilation abortException, + CompilationUnitDeclaration unit) { + + /* special treatment for SilentAbort: silently cancelling the compilation process */ + if (abortException.isSilent) { + if (abortException.silentException == null) { + return; + } else { + throw abortException.silentException; + } + } + + /* uncomment following line to see where the abort came from */ + // abortException.printStackTrace(); + + // Exception may tell which compilation result it is related, and which problem caused it + CompilationResult result = abortException.compilationResult; + if ((result == null) && (unit != null)) + result = unit.compilationResult; // current unit being processed ? + if ((result == null) && (unitsToProcess != null) && (totalUnits > 0)) + result = unitsToProcess[totalUnits - 1].compilationResult; + // last unit in beginToCompile ? + if (result != null && !result.hasBeenAccepted) { + /* distant problem which could not be reported back there */ + if (abortException.problemId != 0) { + result + .record( + problemReporter + .createProblem( + result.getFileName(), + abortException.problemId, + abortException.problemArguments, + Error, // severity + 0, // source start + 0, // source end + 0, // line number + unit, + result), + unit); + } else { + /* distant internal exception which could not be reported back there */ + if (abortException.exception != null) { + this.handleInternalException(abortException.exception, null, result); + return; + } + } + /* hand back the compilation result */ + if (!result.hasBeenAccepted) { + requestor.acceptResult(result.tagAsAccepted()); + } + } else { + /* + if (abortException.problemId != 0){ + IProblem problem = + problemReporter.createProblem( + "???".toCharArray(), + abortException.problemId, + abortException.problemArguments, + Error, // severity + 0, // source start + 0, // source end + 0); // line number + System.out.println(problem.getMessage()); + } + */ + abortException.printStackTrace(); + } + } + + /** + * Process a compilation unit already parsed and build. + */ + private void process(CompilationUnitDeclaration unit, int i) { + + getMethodBodies(unit, i); + + // fault in fields & methods + if (unit.scope != null) + unit.scope.faultInTypes(); + + // verify inherited methods + if (unit.scope != null) + unit.scope.verifyMethods(lookupEnvironment.methodVerifier()); + + // type checking + unit.resolve(); + + // flow analysis + unit.analyseCode(); + + // code generation + unit.generateCode(); + + // reference info + if (options.produceReferenceInfo && unit.scope != null) + unit.scope.storeDependencyInfo(); + + // refresh the total number of units known at this stage + unit.compilationResult.totalUnitsKnown = totalUnits; + } + public void reset() { + lookupEnvironment.reset(); + parser.scanner.source = null; + unitsToProcess = null; + if (DebugRequestor != null) DebugRequestor.reset(); + } + + /** + * Internal API used to resolve a compilation unit minimally for code assist engine + */ + public CompilationUnitDeclaration resolve(ICompilationUnit sourceUnit) { + CompilationUnitDeclaration unit = null; + try { + // build and record parsed units + parseThreshold = 0; // will request a full parse + beginToCompile(new ICompilationUnit[] { sourceUnit }); + // process all units (some more could be injected in the loop by the lookup environment) + unit = unitsToProcess[0]; + getMethodBodies(unit, 0); + if (unit.scope != null) { + // fault in fields & methods + unit.scope.faultInTypes(); + // type checking + unit.resolve(); + } + unitsToProcess[0] = null; // release reference to processed unit declaration + requestor.acceptResult(unit.compilationResult.tagAsAccepted()); + return unit; + } catch (AbortCompilation e) { + this.handleInternalException(e, unit); + return unit == null ? unitsToProcess[0] : unit; + } catch (Error e) { + this.handleInternalException(e, unit, null); + throw e; // rethrow + } catch (RuntimeException e) { + this.handleInternalException(e, unit, null); + throw e; // rethrow + } finally { + // No reset is performed there anymore since, + // within the CodeAssist (or related tools), + // the compiler may be called *after* a call + // to this resolve(...) method. And such a call + // needs to have a compiler with a non-empty + // environment. + // this.reset(); + } + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ConfigurableOption.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ConfigurableOption.java new file mode 100644 index 0000000..e1a64ce --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ConfigurableOption.java @@ -0,0 +1,229 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler; + +/** + * Generic option description, which can be modified independently from the + * component it belongs to. + * + * @deprecated backport 1.0 internal functionality + */ + +import java.util.*; + +public class ConfigurableOption { + private String componentName; + private String optionName; + private int id; + + private String category; + private String name; + private String description; + private int currentValueIndex; + private int defaultValueIndex; + private String[] possibleValues; + + // special value for indicating that + // the is the actual value + public final static String[] NoDiscreteValue = {}; +/** + * INTERNAL USE ONLY + * + * Initialize an instance of this class according to a specific locale + * + * @param loc java.util.Locale + */ +public ConfigurableOption( + String componentName, + String optionName, + Locale loc, + int currentValueIndex) { + + this.componentName = componentName; + this.optionName = optionName; + this.currentValueIndex = currentValueIndex; + + ResourceBundle resource = null; + try { + String location = componentName.substring(0, componentName.lastIndexOf('.')); + resource = ResourceBundle.getBundle(location + ".Options", loc); //$NON-NLS-1$ + } catch (MissingResourceException e) { + category = "Missing ressources entries for" + componentName + " options"; //$NON-NLS-1$ //$NON-NLS-2$ + name = "Missing ressources entries for"+ componentName + " options"; //$NON-NLS-1$ //$NON-NLS-2$ + description = "Missing ressources entries for" + componentName + " options"; //$NON-NLS-1$ //$NON-NLS-2$ + possibleValues = new String[0]; + id = -1; + } + if (resource == null) return; + try { + id = Integer.parseInt(resource.getString(optionName + ".number")); //$NON-NLS-1$ + } catch (MissingResourceException e) { + id = -1; + } catch (NumberFormatException e) { + id = -1; + } + try { + category = resource.getString(optionName + ".category"); //$NON-NLS-1$ + } catch (MissingResourceException e) { + category = "Missing ressources entries for" + componentName + " options"; //$NON-NLS-1$ //$NON-NLS-2$ + } + try { + name = resource.getString(optionName + ".name"); //$NON-NLS-1$ + } catch (MissingResourceException e) { + name = "Missing ressources entries for"+ componentName + " options"; //$NON-NLS-1$ //$NON-NLS-2$ + } + try { + StringTokenizer tokenizer = new StringTokenizer(resource.getString(optionName + ".possibleValues"), "|"); //$NON-NLS-1$ //$NON-NLS-2$ + int numberOfValues = Integer.parseInt(tokenizer.nextToken()); + if(numberOfValues == -1){ + possibleValues = NoDiscreteValue; + } else { + possibleValues = new String[numberOfValues]; + int index = 0; + while (tokenizer.hasMoreTokens()) { + possibleValues[index] = tokenizer.nextToken(); + index++; + } + } + } catch (MissingResourceException e) { + possibleValues = new String[0]; + } catch (NoSuchElementException e) { + possibleValues = new String[0]; + } catch (NumberFormatException e) { + possibleValues = new String[0]; + } + try { + description = resource.getString(optionName + ".description"); //$NON-NLS-1$ + } catch (MissingResourceException e) { + description = "Missing ressources entries for"+ componentName + " options"; //$NON-NLS-1$ //$NON-NLS-2$ + } +} +/** + * Return a String that represents the localized category of the receiver. + * @return java.lang.String + */ +public String getCategory() { + return category; +} +/** + * Return a String that identifies the component owner (typically the qualified + * type name of the class which it corresponds to). + * + * e.g. "org.eclipse.jdt.internal.compiler.api.Compiler" + * + * @return java.lang.String + */ +public String getComponentName() { + return componentName; +} +/** + * Answer the index (in possibleValues array) of the current setting for this + * particular option. + * + * In case the set of possibleValues is NoDiscreteValue, then this index is the + * actual value (e.g. max line lenght set to 80). + * + * @return int + */ +public int getCurrentValueIndex() { + return currentValueIndex; +} +/** + * Answer the index (in possibleValues array) of the default setting for this + * particular option. + * + * In case the set of possibleValues is NoDiscreteValue, then this index is the + * actual value (e.g. max line lenght set to 80). + * + * @return int + */ +public int getDefaultValueIndex() { + return defaultValueIndex; +} +/** + * Return an String that represents the localized description of the receiver. + * + * @return java.lang.String + */ +public String getDescription() { + return description; +} +/** + * Internal ID which allows the configurable component to identify this particular option. + * + * @return int + */ +public int getID() { + return id; +} +/** + * Return a String that represents the localized name of the receiver. + * @return java.lang.String + */ +public String getName() { + return name; +} +/** + * Return an array of String that represents the localized possible values of the receiver. + * @return java.lang.String[] + */ +public String[] getPossibleValues() { + return possibleValues; +} +/** + * Change the index (in possibleValues array) of the current setting for this + * particular option. + * + * In case the set of possibleValues is NoDiscreteValue, then this index is the + * actual value (e.g. max line lenght set to 80). + * + * @return int + */ +public void setValueIndex(int newIndex) { + currentValueIndex = newIndex; +} +public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("Configurable option for "); //$NON-NLS-1$ + buffer.append(this.componentName).append("\n"); //$NON-NLS-1$ + buffer.append("- category: ").append(this.category).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$ + buffer.append("- name: ").append(this.name).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$ + /* display current value */ + buffer.append("- current value: "); //$NON-NLS-1$ + if (possibleValues == NoDiscreteValue){ + buffer.append(this.currentValueIndex); + } else { + buffer.append(this.possibleValues[this.currentValueIndex]); + } + buffer.append("\n"); //$NON-NLS-1$ + + /* display possible values */ + if (possibleValues != NoDiscreteValue){ + buffer.append("- possible values: ["); //$NON-NLS-1$ + for (int i = 0, max = possibleValues.length; i < max; i++) { + if (i != 0) + buffer.append(", "); //$NON-NLS-1$ + buffer.append(possibleValues[i]); + } + buffer.append("]\n"); //$NON-NLS-1$ + buffer.append("- curr. val. index: ").append(currentValueIndex).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$ + } + buffer.append("- description: ").append(description).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$ + return buffer.toString(); +} + /** + * Gets the optionName. + * @return Returns a String + */ + public String getOptionName() { + return optionName; + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/DefaultErrorHandlingPolicies.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/DefaultErrorHandlingPolicies.java new file mode 100644 index 0000000..4144cba --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/DefaultErrorHandlingPolicies.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler; + +public class DefaultErrorHandlingPolicies { + +/* + * Accumulate all problems, then exit without proceeding. + * + * Typically, the #proceedWithProblems(Problem[]) should + * show the problems. + * + */ +public static IErrorHandlingPolicy exitAfterAllProblems() { + return new IErrorHandlingPolicy() { + public boolean stopOnFirstError() { + return false; + } + public boolean proceedOnErrors(){ + return false; + } + }; +} +/* + * Exit without proceeding on the first problem wich appears + * to be an error. + * + */ +public static IErrorHandlingPolicy exitOnFirstError() { + return new IErrorHandlingPolicy() { + public boolean stopOnFirstError() { + return true; + } + public boolean proceedOnErrors(){ + return false; + } + }; +} +/* + * Proceed on the first error met. + * + */ +public static IErrorHandlingPolicy proceedOnFirstError() { + return new IErrorHandlingPolicy() { + public boolean stopOnFirstError() { + return true; + } + public boolean proceedOnErrors(){ + return true; + } + }; +} +/* + * Accumulate all problems, then proceed with them. + * + */ +public static IErrorHandlingPolicy proceedWithAllProblems() { + return new IErrorHandlingPolicy() { + public boolean stopOnFirstError() { + return false; + } + public boolean proceedOnErrors(){ + return true; + } + }; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/DocumentElementParser.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/DocumentElementParser.java new file mode 100644 index 0000000..a94618b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/DocumentElementParser.java @@ -0,0 +1,1328 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler; + +/* + * A document element parser extracts structural information + * from a piece of source, providing detailed source positions info. + * + * also see @IDocumentElementRequestor + * + * The structural investigation includes: + * - the package statement + * - import statements + * - top-level types: package member, member types (member types of member types...) + * - fields + * - methods + * + * Any (parsing) problem encountered is also provided. + */ +import net.sourceforge.phpdt.internal.compiler.env.*; + +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.core.compiler.*; +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.parser.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; +import net.sourceforge.phpdt.internal.compiler.util.*; + +public class DocumentElementParser extends Parser { + IDocumentElementRequestor requestor; + private int localIntPtr; + private int lastFieldEndPosition; + private int lastFieldBodyEndPosition; + private int typeStartPosition; + private long selectorSourcePositions; + private int typeDims; + private int extendsDim; + private int declarationSourceStart; + + /* int[] stack for storing javadoc positions */ + int[][] intArrayStack; + int intArrayPtr; + + CompilerOptions options; + +public DocumentElementParser( + final IDocumentElementRequestor requestor, + IProblemFactory problemFactory, + CompilerOptions options) { + super(new ProblemReporter( + DefaultErrorHandlingPolicies.exitAfterAllProblems(), + options, + problemFactory) { + public void record(IProblem problem, CompilationResult unitResult) { + requestor.acceptProblem(problem); + } + }, + false, + options.assertMode); + this.requestor = requestor; + intArrayStack = new int[30][]; + this.options = options; +} + +/** + * + * INTERNAL USE-ONLY + */ +protected void adjustInterfaceModifiers() { + intStack[intPtr - 2] |= AccInterface; +} +/* + * Will clear the comment stack when looking + * for a potential JavaDoc which might contain @deprecated. + * + * Additionally, before investigating for @deprecated, retrieve the positions + * of the JavaDoc comments so as to notify requestor with them. + */ +public void checkAnnotation() { + + /* persisting javadoc positions */ + pushOnIntArrayStack(this.getJavaDocPositions()); + boolean deprecated = false; + int lastAnnotationIndex = -1; + + //since jdk1.2 look only in the last java doc comment... + found : { + if ((lastAnnotationIndex = scanner.commentPtr) >= 0) { //look for @deprecated + scanner.commentPtr = -1; + // reset the comment stack, since not necessary after having checked + int commentSourceStart = scanner.commentStarts[lastAnnotationIndex]; + // javadoc only (non javadoc comment have negative end positions.) + int commentSourceEnd = scanner.commentStops[lastAnnotationIndex] - 1; + //stop is one over + char[] comment = scanner.source; + + for (int i = commentSourceStart + 3; i < commentSourceEnd - 10; i++) { + if ((comment[i] == '@') + && (comment[i + 1] == 'd') + && (comment[i + 2] == 'e') + && (comment[i + 3] == 'p') + && (comment[i + 4] == 'r') + && (comment[i + 5] == 'e') + && (comment[i + 6] == 'c') + && (comment[i + 7] == 'a') + && (comment[i + 8] == 't') + && (comment[i + 9] == 'e') + && (comment[i + 10] == 'd')) { + // ensure the tag is properly ended: either followed by a space, line end or asterisk. + int nextPos = i + 11; + deprecated = + (comment[nextPos] == ' ') + || (comment[nextPos] == '\n') + || (comment[nextPos] == '\r') + || (comment[nextPos] == '*'); + break found; + } + } + } + } + if (deprecated) { + checkAndSetModifiers(AccDeprecated); + } + // modify the modifier source start to point at the first comment + if (lastAnnotationIndex >= 0) { + declarationSourceStart = scanner.commentStarts[0]; + } +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeClassBodyDeclaration() { + // ClassBodyDeclaration ::= Diet Block + //push an Initializer + //optimize the push/pop + + super.consumeClassBodyDeclaration(); + Initializer initializer = (Initializer) astStack[astPtr]; + requestor.acceptInitializer( + initializer.declarationSourceStart, + initializer.declarationSourceEnd, + intArrayStack[intArrayPtr--], + 0, + modifiersSourceStart, + initializer.block.sourceStart, + initializer.block.sourceEnd); +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeClassDeclaration() { + super.consumeClassDeclaration(); + // we know that we have a TypeDeclaration on the top of the astStack + if (isLocalDeclaration()) { + // we ignore the local variable declarations + return; + } + requestor.exitClass(endStatementPosition, // '}' is the end of the body + ((TypeDeclaration) astStack[astPtr]).declarationSourceEnd); +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeClassHeader() { + //ClassHeader ::= $empty + super.consumeClassHeader(); + if (isLocalDeclaration()) { + // we ignore the local variable declarations + intArrayPtr--; + return; + } + TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr]; + TypeReference[] superInterfaces = typeDecl.superInterfaces; + char[][] interfaceNames = null; + int[] interfaceNameStarts = null; + int[] interfaceNameEnds = null; + if (superInterfaces != null) { + int superInterfacesLength = superInterfaces.length; + interfaceNames = new char[superInterfacesLength][]; + interfaceNameStarts = new int[superInterfacesLength]; + interfaceNameEnds = new int[superInterfacesLength]; + for (int i = 0; i < superInterfacesLength; i++) { + TypeReference superInterface = superInterfaces[i]; + interfaceNames[i] = CharOperation.concatWith(superInterface.getTypeName(), '.'); + interfaceNameStarts[i] = superInterface.sourceStart; + interfaceNameEnds[i] = superInterface.sourceEnd; + } + } + // flush the comments related to the class header + scanner.commentPtr = -1; + TypeReference superclass = typeDecl.superclass; + if (superclass == null) { + requestor.enterClass( + typeDecl.declarationSourceStart, + intArrayStack[intArrayPtr--], + typeDecl.modifiers, + typeDecl.modifiersSourceStart, + typeStartPosition, + typeDecl.name, + typeDecl.sourceStart, + typeDecl.sourceEnd, + null, + -1, + -1, + interfaceNames, + interfaceNameStarts, + interfaceNameEnds, + scanner.currentPosition - 1); + } else { + requestor.enterClass( + typeDecl.declarationSourceStart, + intArrayStack[intArrayPtr--], + typeDecl.modifiers, + typeDecl.modifiersSourceStart, + typeStartPosition, + typeDecl.name, + typeDecl.sourceStart, + typeDecl.sourceEnd, + CharOperation.concatWith(superclass.getTypeName(), '.'), + superclass.sourceStart, + superclass.sourceEnd, + interfaceNames, + interfaceNameStarts, + interfaceNameEnds, + scanner.currentPosition - 1); + + } +} +protected void consumeClassHeaderName() { + // ClassHeaderName ::= Modifiersopt 'class' 'Identifier' + TypeDeclaration typeDecl; + if (nestedMethod[nestedType] == 0) { + if (nestedType != 0) { + typeDecl = new MemberTypeDeclaration(this.compilationUnit.compilationResult); + } else { + typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult); + } + } else { + // Record that the block has a declaration for local types + typeDecl = new LocalTypeDeclaration(this.compilationUnit.compilationResult); + markCurrentMethodWithLocalType(); + blockReal(); + } + + //highlight the name of the type + long pos = identifierPositionStack[identifierPtr]; + typeDecl.sourceEnd = (int) pos; + typeDecl.sourceStart = (int) (pos >>> 32); + typeDecl.name = identifierStack[identifierPtr--]; + identifierLengthPtr--; + + //compute the declaration source too + // 'class' and 'interface' push an int position + typeStartPosition = typeDecl.declarationSourceStart = intStack[intPtr--]; + intPtr--; + int declarationSourceStart = intStack[intPtr--]; + typeDecl.modifiersSourceStart = intStack[intPtr--]; + typeDecl.modifiers = intStack[intPtr--]; + if (typeDecl.declarationSourceStart > declarationSourceStart) { + typeDecl.declarationSourceStart = declarationSourceStart; + } + typeDecl.bodyStart = typeDecl.sourceEnd + 1; + pushOnAstStack(typeDecl); +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeCompilationUnit() { + // CompilationUnit ::= EnterCompilationUnit PackageDeclarationopt ImportDeclarationsopt + requestor.exitCompilationUnit(scanner.source.length - 1); +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeConstructorDeclaration() { + // ConstructorDeclaration ::= ConstructorHeader ConstructorBody + super.consumeConstructorDeclaration(); + if (isLocalDeclaration()) { + // we ignore the local variable declarations + return; + } + ConstructorDeclaration cd = (ConstructorDeclaration) astStack[astPtr]; + requestor.exitConstructor(endStatementPosition, cd.declarationSourceEnd); +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeConstructorHeader() { + // ConstructorHeader ::= ConstructorHeaderName MethodHeaderParameters MethodHeaderThrowsClauseopt + super.consumeConstructorHeader(); + if (isLocalDeclaration()) { + // we ignore the local variable declarations + intArrayPtr--; + return; + } + ConstructorDeclaration cd = (ConstructorDeclaration) astStack[astPtr]; + Argument[] arguments = cd.arguments; + char[][] argumentTypes = null; + char[][] argumentNames = null; + int[] argumentTypeStarts = null; + int[] argumentTypeEnds = null; + int[] argumentNameStarts = null; + int[] argumentNameEnds = null; + if (arguments != null) { + int argumentLength = arguments.length; + argumentTypes = new char[argumentLength][]; + argumentNames = new char[argumentLength][]; + argumentNameStarts = new int[argumentLength]; + argumentNameEnds = new int[argumentLength]; + argumentTypeStarts = new int[argumentLength]; + argumentTypeEnds = new int[argumentLength]; + for (int i = 0; i < argumentLength; i++) { + Argument argument = arguments[i]; + TypeReference argumentType = argument.type; + argumentTypes[i] = returnTypeName(argumentType); + argumentNames[i] = argument.name; + argumentNameStarts[i] = argument.sourceStart; + argumentNameEnds[i] = argument.sourceEnd; + argumentTypeStarts[i] = argumentType.sourceStart; + argumentTypeEnds[i] = argumentType.sourceEnd; + } + } + TypeReference[] thrownExceptions = cd.thrownExceptions; + char[][] exceptionTypes = null; + int[] exceptionTypeStarts = null; + int[] exceptionTypeEnds = null; + if (thrownExceptions != null) { + int thrownExceptionLength = thrownExceptions.length; + exceptionTypes = new char[thrownExceptionLength][]; + exceptionTypeStarts = new int[thrownExceptionLength]; + exceptionTypeEnds = new int[thrownExceptionLength]; + for (int i = 0; i < thrownExceptionLength; i++) { + TypeReference exception = thrownExceptions[i]; + exceptionTypes[i] = CharOperation.concatWith(exception.getTypeName(), '.'); + exceptionTypeStarts[i] = exception.sourceStart; + exceptionTypeEnds[i] = exception.sourceEnd; + } + } + requestor + .enterConstructor( + cd.declarationSourceStart, + intArrayStack[intArrayPtr--], + cd.modifiers, + cd.modifiersSourceStart, + cd.selector, + cd.sourceStart, + (int) (selectorSourcePositions & 0xFFFFFFFFL), + // retrieve the source end of the name + argumentTypes, + argumentTypeStarts, + argumentTypeEnds, + argumentNames, + argumentNameStarts, + argumentNameEnds, + rParenPos, + // right parenthesis + exceptionTypes, + exceptionTypeStarts, + exceptionTypeEnds, + scanner.currentPosition - 1); +} +protected void consumeConstructorHeaderName() { + // ConstructorHeaderName ::= Modifiersopt 'Identifier' '(' + ConstructorDeclaration cd = new ConstructorDeclaration(this.compilationUnit.compilationResult); + + //name -- this is not really revelant but we do ..... + cd.selector = identifierStack[identifierPtr]; + selectorSourcePositions = identifierPositionStack[identifierPtr--]; + identifierLengthPtr--; + + //modifiers + cd.declarationSourceStart = intStack[intPtr--]; + cd.modifiersSourceStart = intStack[intPtr--]; + cd.modifiers = intStack[intPtr--]; + + //highlight starts at the selector starts + cd.sourceStart = (int) (selectorSourcePositions >>> 32); + pushOnAstStack(cd); + + cd.sourceEnd = lParenPos; + cd.bodyStart = lParenPos + 1; +} +protected void consumeDefaultModifiers() { + checkAnnotation(); // might update modifiers with AccDeprecated + pushOnIntStack(modifiers); // modifiers + pushOnIntStack(-1); + pushOnIntStack( + declarationSourceStart >= 0 ? declarationSourceStart : scanner.startPosition); + resetModifiers(); +} +protected void consumeDiet() { + // Diet ::= $empty + super.consumeDiet(); + /* persisting javadoc positions + * Will be consume in consumeClassBodyDeclaration + */ + pushOnIntArrayStack(this.getJavaDocPositions()); +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeEnterCompilationUnit() { + // EnterCompilationUnit ::= $empty + requestor.enterCompilationUnit(); +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeEnterVariable() { + // EnterVariable ::= $empty + boolean isLocalDeclaration = isLocalDeclaration(); + if (!isLocalDeclaration && (variablesCounter[nestedType] != 0)) { + requestor.exitField(lastFieldBodyEndPosition, lastFieldEndPosition); + } + char[] name = identifierStack[identifierPtr]; + long namePosition = identifierPositionStack[identifierPtr--]; + int extendedTypeDimension = intStack[intPtr--]; + + AbstractVariableDeclaration declaration; + if (nestedMethod[nestedType] != 0) { + // create the local variable declarations + declaration = + new LocalDeclaration(null, name, (int) (namePosition >>> 32), (int) namePosition); + } else { + // create the field declaration + declaration = + new FieldDeclaration(null, name, (int) (namePosition >>> 32), (int) namePosition); + } + identifierLengthPtr--; + TypeReference type; + int variableIndex = variablesCounter[nestedType]; + int typeDim = 0; + if (variableIndex == 0) { + // first variable of the declaration (FieldDeclaration or LocalDeclaration) + if (nestedMethod[nestedType] != 0) { + // local declaration + declaration.declarationSourceStart = intStack[intPtr--]; + declaration.modifiersSourceStart = intStack[intPtr--]; + declaration.modifiers = intStack[intPtr--]; + type = getTypeReference(typeDim = intStack[intPtr--]); // type dimension + pushOnAstStack(type); + } else { + // field declaration + type = getTypeReference(typeDim = intStack[intPtr--]); // type dimension + pushOnAstStack(type); + declaration.declarationSourceStart = intStack[intPtr--]; + declaration.modifiersSourceStart = intStack[intPtr--]; + declaration.modifiers = intStack[intPtr--]; + } + } else { + type = (TypeReference) astStack[astPtr - variableIndex]; + typeDim = type.dimensions(); + AbstractVariableDeclaration previousVariable = + (AbstractVariableDeclaration) astStack[astPtr]; + declaration.declarationSourceStart = previousVariable.declarationSourceStart; + declaration.modifiers = previousVariable.modifiers; + declaration.modifiersSourceStart = previousVariable.modifiersSourceStart; + } + + localIntPtr = intPtr; + + if (extendedTypeDimension == 0) { + declaration.type = type; + } else { + int dimension = typeDim + extendedTypeDimension; + //on the identifierLengthStack there is the information about the type.... + int baseType; + if ((baseType = identifierLengthStack[identifierLengthPtr + 1]) < 0) { + //it was a baseType + declaration.type = TypeReference.baseTypeReference(-baseType, dimension); + declaration.type.sourceStart = type.sourceStart; + declaration.type.sourceEnd = type.sourceEnd; + } else { + declaration.type = this.copyDims(type, dimension); + } + } + variablesCounter[nestedType]++; + nestedMethod[nestedType]++; + pushOnAstStack(declaration); + + int[] javadocPositions = intArrayStack[intArrayPtr]; + if (!isLocalDeclaration) { + requestor + .enterField( + declaration.declarationSourceStart, + javadocPositions, + declaration.modifiers, + declaration.modifiersSourceStart, + returnTypeName(declaration.type), + type.sourceStart, + type.sourceEnd, + typeDims, + name, + (int) (namePosition >>> 32), + (int) namePosition, + extendedTypeDimension, + extendedTypeDimension == 0 ? -1 : endPosition); + } +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeExitVariableWithInitialization() { + // ExitVariableWithInitialization ::= $empty + // the scanner is located after the comma or the semi-colon. + // we want to include the comma or the semi-colon + super.consumeExitVariableWithInitialization(); + nestedMethod[nestedType]--; + lastFieldEndPosition = scanner.currentPosition - 1; + lastFieldBodyEndPosition = ((AbstractVariableDeclaration) astStack[astPtr]).initialization.sourceEnd; +} +protected void consumeExitVariableWithoutInitialization() { + // ExitVariableWithoutInitialization ::= $empty + // do nothing by default + super.consumeExitVariableWithoutInitialization(); + nestedMethod[nestedType]--; + lastFieldEndPosition = scanner.currentPosition - 1; + lastFieldBodyEndPosition = scanner.startPosition - 1; +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeFieldDeclaration() { + // See consumeLocalVariableDeclarationDefaultModifier() in case of change: duplicated code + // FieldDeclaration ::= Modifiersopt Type VariableDeclarators ';' + // the super.consumeFieldDeclaration will reinitialize the variableCounter[nestedType] + int variableIndex = variablesCounter[nestedType]; + super.consumeFieldDeclaration(); + intArrayPtr--; + if (isLocalDeclaration()) + return; + if (variableIndex != 0) { + requestor.exitField(lastFieldBodyEndPosition, lastFieldEndPosition); + } +} +protected void consumeFormalParameter() { + // FormalParameter ::= Type VariableDeclaratorId ==> false + // FormalParameter ::= Modifiers Type VariableDeclaratorId ==> true + /* + astStack : + identifierStack : type identifier + intStack : dim dim + ==> + astStack : Argument + identifierStack : + intStack : + */ + + identifierLengthPtr--; + char[] name = identifierStack[identifierPtr]; + long namePositions = identifierPositionStack[identifierPtr--]; + TypeReference type = getTypeReference(intStack[intPtr--] + intStack[intPtr--]); + intPtr -= 3; + Argument arg = + new Argument( + name, + namePositions, + type, + intStack[intPtr + 1]); // modifiers + pushOnAstStack(arg); + intArrayPtr--; +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeInterfaceDeclaration() { + super.consumeInterfaceDeclaration(); + // we know that we have a TypeDeclaration on the top of the astStack + if (isLocalDeclaration()) { + // we ignore the local variable declarations + return; + } + requestor.exitInterface(endStatementPosition, // the '}' is the end of the body + ((TypeDeclaration) astStack[astPtr]).declarationSourceEnd); +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeInterfaceHeader() { + //InterfaceHeader ::= $empty + super.consumeInterfaceHeader(); + if (isLocalDeclaration()) { + // we ignore the local variable declarations + intArrayPtr--; + return; + } + TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr]; + TypeReference[] superInterfaces = typeDecl.superInterfaces; + char[][] interfaceNames = null; + int[] interfaceNameStarts = null; + int[] interfacenameEnds = null; + int superInterfacesLength = 0; + if (superInterfaces != null) { + superInterfacesLength = superInterfaces.length; + interfaceNames = new char[superInterfacesLength][]; + interfaceNameStarts = new int[superInterfacesLength]; + interfacenameEnds = new int[superInterfacesLength]; + } + if (superInterfaces != null) { + for (int i = 0; i < superInterfacesLength; i++) { + TypeReference superInterface = superInterfaces[i]; + interfaceNames[i] = CharOperation.concatWith(superInterface.getTypeName(), '.'); + interfaceNameStarts[i] = superInterface.sourceStart; + interfacenameEnds[i] = superInterface.sourceEnd; + } + } + // flush the comments related to the interface header + scanner.commentPtr = -1; + requestor.enterInterface( + typeDecl.declarationSourceStart, + intArrayStack[intArrayPtr--], + typeDecl.modifiers, + typeDecl.modifiersSourceStart, + typeStartPosition, + typeDecl.name, + typeDecl.sourceStart, + typeDecl.sourceEnd, + interfaceNames, + interfaceNameStarts, + interfacenameEnds, + scanner.currentPosition - 1); +} +protected void consumeInterfaceHeaderName() { + // InterfaceHeaderName ::= Modifiersopt 'interface' 'Identifier' + TypeDeclaration typeDecl; + if (nestedMethod[nestedType] == 0) { + if (nestedType != 0) { + typeDecl = new MemberTypeDeclaration(this.compilationUnit.compilationResult); + } else { + typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult); + } + } else { + // Record that the block has a declaration for local types + typeDecl = new LocalTypeDeclaration(this.compilationUnit.compilationResult); + markCurrentMethodWithLocalType(); + blockReal(); + } + + //highlight the name of the type + long pos = identifierPositionStack[identifierPtr]; + typeDecl.sourceEnd = (int) pos; + typeDecl.sourceStart = (int) (pos >>> 32); + typeDecl.name = identifierStack[identifierPtr--]; + identifierLengthPtr--; + + //compute the declaration source too + // 'class' and 'interface' push an int position + typeStartPosition = typeDecl.declarationSourceStart = intStack[intPtr--]; + intPtr--; + int declarationSourceStart = intStack[intPtr--]; + typeDecl.modifiersSourceStart = intStack[intPtr--]; + typeDecl.modifiers = intStack[intPtr--]; + if (typeDecl.declarationSourceStart > declarationSourceStart) { + typeDecl.declarationSourceStart = declarationSourceStart; + } + typeDecl.bodyStart = typeDecl.sourceEnd + 1; + pushOnAstStack(typeDecl); +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeLocalVariableDeclaration() { + // See consumeLocalVariableDeclarationDefaultModifier() in case of change: duplicated code + // FieldDeclaration ::= Modifiersopt Type VariableDeclarators ';' + + super.consumeLocalVariableDeclaration(); + intArrayPtr--; +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeMethodDeclaration(boolean isNotAbstract) { + // MethodDeclaration ::= MethodHeader MethodBody + // AbstractMethodDeclaration ::= MethodHeader ';' + super.consumeMethodDeclaration(isNotAbstract); + if (isLocalDeclaration()) { + // we ignore the local variable declarations + return; + } + MethodDeclaration md = (MethodDeclaration) astStack[astPtr]; + requestor.exitMethod(endStatementPosition, md.declarationSourceEnd); +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeMethodHeader() { + // MethodHeader ::= MethodHeaderName MethodHeaderParameters MethodHeaderExtendedDims ThrowsClauseopt + super.consumeMethodHeader(); + if (isLocalDeclaration()) { + // we ignore the local variable declarations + intArrayPtr--; + return; + } + MethodDeclaration md = (MethodDeclaration) astStack[astPtr]; + + TypeReference returnType = md.returnType; + char[] returnTypeName = returnTypeName(returnType); + Argument[] arguments = md.arguments; + char[][] argumentTypes = null; + char[][] argumentNames = null; + int[] argumentTypeStarts = null; + int[] argumentTypeEnds = null; + int[] argumentNameStarts = null; + int[] argumentNameEnds = null; + if (arguments != null) { + int argumentLength = arguments.length; + argumentTypes = new char[argumentLength][]; + argumentNames = new char[argumentLength][]; + argumentNameStarts = new int[argumentLength]; + argumentNameEnds = new int[argumentLength]; + argumentTypeStarts = new int[argumentLength]; + argumentTypeEnds = new int[argumentLength]; + for (int i = 0; i < argumentLength; i++) { + Argument argument = arguments[i]; + TypeReference argumentType = argument.type; + argumentTypes[i] = returnTypeName(argumentType); + argumentNames[i] = argument.name; + argumentNameStarts[i] = argument.sourceStart; + argumentNameEnds[i] = argument.sourceEnd; + argumentTypeStarts[i] = argumentType.sourceStart; + argumentTypeEnds[i] = argumentType.sourceEnd; + } + } + TypeReference[] thrownExceptions = md.thrownExceptions; + char[][] exceptionTypes = null; + int[] exceptionTypeStarts = null; + int[] exceptionTypeEnds = null; + if (thrownExceptions != null) { + int thrownExceptionLength = thrownExceptions.length; + exceptionTypeStarts = new int[thrownExceptionLength]; + exceptionTypeEnds = new int[thrownExceptionLength]; + exceptionTypes = new char[thrownExceptionLength][]; + for (int i = 0; i < thrownExceptionLength; i++) { + TypeReference exception = thrownExceptions[i]; + exceptionTypes[i] = CharOperation.concatWith(exception.getTypeName(), '.'); + exceptionTypeStarts[i] = exception.sourceStart; + exceptionTypeEnds[i] = exception.sourceEnd; + } + } + requestor + .enterMethod( + md.declarationSourceStart, + intArrayStack[intArrayPtr--], + md.modifiers, + md.modifiersSourceStart, + returnTypeName, + returnType.sourceStart, + returnType.sourceEnd, + typeDims, + md.selector, + md.sourceStart, + (int) (selectorSourcePositions & 0xFFFFFFFFL), + argumentTypes, + argumentTypeStarts, + argumentTypeEnds, + argumentNames, + argumentNameStarts, + argumentNameEnds, + rParenPos, + extendsDim, + extendsDim == 0 ? -1 : endPosition, + exceptionTypes, + exceptionTypeStarts, + exceptionTypeEnds, + scanner.currentPosition - 1); +} +protected void consumeMethodHeaderExtendedDims() { + // MethodHeaderExtendedDims ::= Dimsopt + // now we update the returnType of the method + MethodDeclaration md = (MethodDeclaration) astStack[astPtr]; + int extendedDims = intStack[intPtr--]; + extendsDim = extendedDims; + if (extendedDims != 0) { + TypeReference returnType = md.returnType; + md.sourceEnd = endPosition; + int dims = returnType.dimensions() + extendedDims; + int baseType; + if ((baseType = identifierLengthStack[identifierLengthPtr + 1]) < 0) { + //it was a baseType + int sourceStart = returnType.sourceStart; + int sourceEnd = returnType.sourceEnd; + returnType = TypeReference.baseTypeReference(-baseType, dims); + returnType.sourceStart = sourceStart; + returnType.sourceEnd = sourceEnd; + md.returnType = returnType; + } else { + md.returnType = this.copyDims(md.returnType, dims); + } + if (currentToken == TokenNameLBRACE) { + md.bodyStart = endPosition + 1; + } + } +} +protected void consumeMethodHeaderName() { + // MethodHeaderName ::= Modifiersopt Type 'Identifier' '(' + MethodDeclaration md = new MethodDeclaration(this.compilationUnit.compilationResult); + + //name + md.selector = identifierStack[identifierPtr]; + selectorSourcePositions = identifierPositionStack[identifierPtr--]; + identifierLengthPtr--; + //type + md.returnType = getTypeReference(typeDims = intStack[intPtr--]); + //modifiers + md.declarationSourceStart = intStack[intPtr--]; + md.modifiersSourceStart = intStack[intPtr--]; + md.modifiers = intStack[intPtr--]; + + //highlight starts at selector start + md.sourceStart = (int) (selectorSourcePositions >>> 32); + pushOnAstStack(md); + md.bodyStart = scanner.currentPosition-1; +} +protected void consumeModifiers() { + checkAnnotation(); // might update modifiers with AccDeprecated + pushOnIntStack(modifiers); // modifiers + pushOnIntStack(modifiersSourceStart); + pushOnIntStack( + declarationSourceStart >= 0 ? declarationSourceStart : modifiersSourceStart); + resetModifiers(); +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumePackageDeclarationName() { + /* persisting javadoc positions */ + pushOnIntArrayStack(this.getJavaDocPositions()); + + super.consumePackageDeclarationName(); + ImportReference importReference = compilationUnit.currentPackage; + + requestor.acceptPackage( + importReference.declarationSourceStart, + importReference.declarationSourceEnd, + intArrayStack[intArrayPtr--], + CharOperation.concatWith(importReference.getImportName(), '.'), + importReference.sourceStart); +} +protected void consumePushModifiers() { + checkAnnotation(); // might update modifiers with AccDeprecated + pushOnIntStack(modifiers); // modifiers + if (modifiersSourceStart < 0) { + pushOnIntStack(-1); + pushOnIntStack( + declarationSourceStart >= 0 ? declarationSourceStart : scanner.startPosition); + } else { + pushOnIntStack(modifiersSourceStart); + pushOnIntStack( + declarationSourceStart >= 0 ? declarationSourceStart : modifiersSourceStart); + } + resetModifiers(); +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeSingleTypeImportDeclarationName() { + // SingleTypeImportDeclarationName ::= 'import' Name + + /* persisting javadoc positions */ + pushOnIntArrayStack(this.getJavaDocPositions()); + + super.consumeSingleTypeImportDeclarationName(); + ImportReference importReference = (ImportReference) astStack[astPtr]; + requestor.acceptImport( + importReference.declarationSourceStart, + importReference.declarationSourceEnd, + intArrayStack[intArrayPtr--], + CharOperation.concatWith(importReference.getImportName(), '.'), + importReference.sourceStart, + false); +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeStaticInitializer() { + // StaticInitializer ::= StaticOnly Block + //push an Initializer + //optimize the push/pop + super.consumeStaticInitializer(); + Initializer initializer = (Initializer) astStack[astPtr]; + requestor.acceptInitializer( + initializer.declarationSourceStart, + initializer.declarationSourceEnd, + intArrayStack[intArrayPtr--], + AccStatic, + intStack[intPtr--], + initializer.block.sourceStart, + initializer.declarationSourceEnd); +} +protected void consumeStaticOnly() { + // StaticOnly ::= 'static' + checkAnnotation(); // might update declaration source start + pushOnIntStack(modifiersSourceStart); + pushOnIntStack( + declarationSourceStart >= 0 ? declarationSourceStart : modifiersSourceStart); + jumpOverMethodBody(); + nestedMethod[nestedType]++; + resetModifiers(); +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeTypeImportOnDemandDeclarationName() { + // TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*' + + /* persisting javadoc positions */ + pushOnIntArrayStack(this.getJavaDocPositions()); + + super.consumeTypeImportOnDemandDeclarationName(); + ImportReference importReference = (ImportReference) astStack[astPtr]; + requestor.acceptImport( + importReference.declarationSourceStart, + importReference.declarationSourceEnd, + intArrayStack[intArrayPtr--], + CharOperation.concatWith(importReference.getImportName(), '.'), + importReference.sourceStart, + true); +} +public CompilationUnitDeclaration endParse(int act) { + if (scanner.recordLineSeparator) { + requestor.acceptLineSeparatorPositions(scanner.getLineEnds()); + } + return super.endParse(act); +} +/* + * Flush annotations defined prior to a given positions. + * + * Note: annotations are stacked in syntactical order + * + * Either answer given , or the end position of a comment line + * immediately following the (same line) + * + * e.g. + * void foo(){ + * } // end of method foo + */ + +public int flushAnnotationsDefinedPriorTo(int position) { + + return lastFieldEndPosition = super.flushAnnotationsDefinedPriorTo(position); +} +protected TypeReference getTypeReference(int dim) { /* build a Reference on a variable that may be qualified or not +This variable is a type reference and dim will be its dimensions*/ + + int length; + TypeReference ref; + if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) { + // single variable reference + if (dim == 0) { + ref = + new SingleTypeReference( + identifierStack[identifierPtr], + identifierPositionStack[identifierPtr--]); + } else { + ref = + new ArrayTypeReference( + identifierStack[identifierPtr], + dim, + identifierPositionStack[identifierPtr--]); + ref.sourceEnd = endPosition; + } + } else { + if (length < 0) { //flag for precompiled type reference on base types + ref = TypeReference.baseTypeReference(-length, dim); + ref.sourceStart = intStack[intPtr--]; + if (dim == 0) { + ref.sourceEnd = intStack[intPtr--]; + } else { + intPtr--; + ref.sourceEnd = endPosition; + } + } else { //Qualified variable reference + char[][] tokens = new char[length][]; + identifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length); + System.arraycopy( + identifierPositionStack, + identifierPtr + 1, + positions, + 0, + length); + if (dim == 0) { + ref = new QualifiedTypeReference(tokens, positions); + } else { + ref = new ArrayQualifiedTypeReference(tokens, dim, positions); + ref.sourceEnd = endPosition; + } + } + }; + return ref; +} +public void initialize() { + //positionning the parser for a new compilation unit + //avoiding stack reallocation and all that.... + super.initialize(); + intArrayPtr = -1; +} +/** + * + * INTERNAL USE-ONLY + */ +private boolean isLocalDeclaration() { + int nestedDepth = nestedType; + while (nestedDepth >= 0) { + if (nestedMethod[nestedDepth] != 0) { + return true; + } + nestedDepth--; + } + return false; +} +/* + * Investigate one entire unit. + */ +public void parseCompilationUnit(ICompilationUnit unit) { + char[] regionSource = unit.getContents(); + try { + initialize(); + goForCompilationUnit(); + referenceContext = + compilationUnit = + compilationUnit = + new CompilationUnitDeclaration( + problemReporter(), + new CompilationResult(unit, 0, 0, this.options.maxProblemsPerUnit), + regionSource.length); + scanner.resetTo(0, regionSource.length); + scanner.setSource(regionSource); + parse(); + } catch (AbortCompilation ex) { + } +} +/* + * Investigate one constructor declaration. + */ +public void parseConstructor(char[] regionSource) { + try { + initialize(); + goForClassBodyDeclarations(); + referenceContext = + compilationUnit = + compilationUnit = + new CompilationUnitDeclaration( + problemReporter(), + new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), + regionSource.length); + scanner.resetTo(0, regionSource.length); + scanner.setSource(regionSource); + parse(); + } catch (AbortCompilation ex) { + } +} +/* + * Investigate one field declaration statement (might have multiple declarations in it). + */ +public void parseField(char[] regionSource) { + try { + initialize(); + goForFieldDeclaration(); + referenceContext = + compilationUnit = + compilationUnit = + new CompilationUnitDeclaration( + problemReporter(), + new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), + regionSource.length); + scanner.resetTo(0, regionSource.length); + scanner.setSource(regionSource); + parse(); + } catch (AbortCompilation ex) { + } + +} +/* + * Investigate one import statement declaration. + */ +public void parseImport(char[] regionSource) { + try { + initialize(); + goForImportDeclaration(); + referenceContext = + compilationUnit = + compilationUnit = + new CompilationUnitDeclaration( + problemReporter(), + new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), + regionSource.length); + scanner.resetTo(0, regionSource.length); + scanner.setSource(regionSource); + parse(); + } catch (AbortCompilation ex) { + } + +} +/* + * Investigate one initializer declaration. + * regionSource need to content exactly an initializer declaration. + * e.g: static { i = 4; } + * { name = "test"; } + */ +public void parseInitializer(char[] regionSource) { + try { + initialize(); + goForInitializer(); + referenceContext = + compilationUnit = + compilationUnit = + new CompilationUnitDeclaration( + problemReporter(), + new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), + regionSource.length); + scanner.resetTo(0, regionSource.length); + scanner.setSource(regionSource); + parse(); + } catch (AbortCompilation ex) { + } + +} +/* + * Investigate one method declaration. + */ +public void parseMethod(char[] regionSource) { + try { + initialize(); + goForGenericMethodDeclaration(); + referenceContext = + compilationUnit = + compilationUnit = + new CompilationUnitDeclaration( + problemReporter(), + new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), + regionSource.length); + scanner.resetTo(0, regionSource.length); + scanner.setSource(regionSource); + parse(); + } catch (AbortCompilation ex) { + } + +} +/* + * Investigate one package statement declaration. + */ +public void parsePackage(char[] regionSource) { + try { + initialize(); + goForPackageDeclaration(); + referenceContext = + compilationUnit = + compilationUnit = + new CompilationUnitDeclaration( + problemReporter(), + new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), + regionSource.length); + scanner.resetTo(0, regionSource.length); + scanner.setSource(regionSource); + parse(); + } catch (AbortCompilation ex) { + } + +} +/* + * Investigate one type declaration, its fields, methods and member types. + */ +public void parseType(char[] regionSource) { + try { + initialize(); + goForTypeDeclaration(); + referenceContext = + compilationUnit = + compilationUnit = + new CompilationUnitDeclaration( + problemReporter(), + new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), + regionSource.length); + scanner.resetTo(0, regionSource.length); + scanner.setSource(regionSource); + parse(); + } catch (AbortCompilation ex) { + } + +} +/** + * Returns this parser's problem reporter initialized with its reference context. + * Also it is assumed that a problem is going to be reported, so initializes + * the compilation result's line positions. + */ +public ProblemReporter problemReporter() { + problemReporter.referenceContext = referenceContext; + return problemReporter; +} +protected void pushOnIntArrayStack(int[] positions) { + + try { + intArrayStack[++intArrayPtr] = positions; + } catch (IndexOutOfBoundsException e) { + //intPtr is correct + int oldStackLength = intArrayStack.length; + int oldStack[][] = intArrayStack; + intArrayStack = new int[oldStackLength + StackIncrement][]; + System.arraycopy(oldStack, 0, intArrayStack, 0, oldStackLength); + intArrayStack[intArrayPtr] = positions; + } +} +protected void resetModifiers() { + super.resetModifiers(); + declarationSourceStart = -1; +} +/* + * Syntax error was detected. Will attempt to perform some recovery action in order + * to resume to the regular parse loop. + */ +protected boolean resumeOnSyntaxError() { + return false; +} +/* + * Answer a char array representation of the type name formatted like: + * - type name + dimensions + * Example: + * "A[][]".toCharArray() + * "java.lang.String".toCharArray() + */ +private char[] returnTypeName(TypeReference type) { + int dimension = type.dimensions(); + if (dimension != 0) { + char[] dimensionsArray = new char[dimension * 2]; + for (int i = 0; i < dimension; i++) { + dimensionsArray[i*2] = '['; + dimensionsArray[(i*2) + 1] = ']'; + } + return CharOperation.concat( + CharOperation.concatWith(type.getTypeName(), '.'), + dimensionsArray); + } + return CharOperation.concatWith(type.getTypeName(), '.'); +} +public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("intArrayPtr = " + intArrayPtr + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ + buffer.append(super.toString()); + return buffer.toString(); +} +/** + * INTERNAL USE ONLY + */ +protected TypeReference typeReference( + int dim, + int localIdentifierPtr, + int localIdentifierLengthPtr) { + /* build a Reference on a variable that may be qualified or not + * This variable is a type reference and dim will be its dimensions. + * We don't have any side effect on the stacks' pointers. + */ + + int length; + TypeReference ref; + if ((length = identifierLengthStack[localIdentifierLengthPtr]) == 1) { + // single variable reference + if (dim == 0) { + ref = + new SingleTypeReference( + identifierStack[localIdentifierPtr], + identifierPositionStack[localIdentifierPtr--]); + } else { + ref = + new ArrayTypeReference( + identifierStack[localIdentifierPtr], + dim, + identifierPositionStack[localIdentifierPtr--]); + ref.sourceEnd = endPosition; + } + } else { + if (length < 0) { //flag for precompiled type reference on base types + ref = TypeReference.baseTypeReference(-length, dim); + ref.sourceStart = intStack[localIntPtr--]; + if (dim == 0) { + ref.sourceEnd = intStack[localIntPtr--]; + } else { + localIntPtr--; + ref.sourceEnd = endPosition; + } + } else { //Qualified variable reference + char[][] tokens = new char[length][]; + localIdentifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy(identifierStack, localIdentifierPtr + 1, tokens, 0, length); + System.arraycopy( + identifierPositionStack, + localIdentifierPtr + 1, + positions, + 0, + length); + if (dim == 0) + ref = new QualifiedTypeReference(tokens, positions); + else + ref = new ArrayQualifiedTypeReference(tokens, dim, positions); + } + }; + return ref; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/IAbstractSyntaxTreeVisitor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/IAbstractSyntaxTreeVisitor.java new file mode 100644 index 0000000..db4efb4 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/IAbstractSyntaxTreeVisitor.java @@ -0,0 +1,172 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler; + +import net.sourceforge.phpdt.core.compiler.*; +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +/** + * A visitor interface for interating through the parse tree. + */ +public interface IAbstractSyntaxTreeVisitor { + void acceptProblem(IProblem problem); + void endVisit(AllocationExpression allocationExpression, BlockScope scope); + void endVisit(AND_AND_Expression and_and_Expression, BlockScope scope); + void endVisit(AnonymousLocalTypeDeclaration anonymousTypeDeclaration, BlockScope scope); + void endVisit(Argument argument, BlockScope scope); + void endVisit(ArrayAllocationExpression arrayAllocationExpression, BlockScope scope); + void endVisit(ArrayInitializer arrayInitializer, BlockScope scope); + void endVisit(ArrayQualifiedTypeReference arrayQualifiedTypeReference, BlockScope scope); + void endVisit(ArrayQualifiedTypeReference arrayQualifiedTypeReference, ClassScope scope); + void endVisit(ArrayReference arrayReference, BlockScope scope); + void endVisit(ArrayTypeReference arrayTypeReference, BlockScope scope); + void endVisit(ArrayTypeReference arrayTypeReference, ClassScope scope); + void endVisit(AssertStatement assertStatement, BlockScope scope); + void endVisit(Assignment assignment, BlockScope scope); + void endVisit(BinaryExpression binaryExpression, BlockScope scope); + void endVisit(Block block, BlockScope scope); + void endVisit(Break breakStatement, BlockScope scope); + void endVisit(Case caseStatement, BlockScope scope); + void endVisit(CastExpression castExpression, BlockScope scope); + void endVisit(CharLiteral charLiteral, BlockScope scope); + void endVisit(ClassLiteralAccess classLiteral, BlockScope scope); + void endVisit(Clinit clinit, ClassScope scope); + void endVisit(CompilationUnitDeclaration compilationUnitDeclaration, CompilationUnitScope scope); + void endVisit(CompoundAssignment compoundAssignment, BlockScope scope); + void endVisit(ConditionalExpression conditionalExpression, BlockScope scope); + void endVisit(ConstructorDeclaration constructorDeclaration, ClassScope scope); + void endVisit(Continue continueStatement, BlockScope scope); + void endVisit(DefaultCase defaultCaseStatement, BlockScope scope); + void endVisit(DoStatement doStatement, BlockScope scope); + void endVisit(DoubleLiteral doubleLiteral, BlockScope scope); + void endVisit(EqualExpression equalExpression, BlockScope scope); + void endVisit(EmptyStatement statement, BlockScope scope); + void endVisit(ExplicitConstructorCall explicitConstructor, BlockScope scope); + void endVisit(ExtendedStringLiteral extendedStringLiteral, BlockScope scope); + void endVisit(FalseLiteral falseLiteral, BlockScope scope); + void endVisit(FieldDeclaration fieldDeclaration, MethodScope scope); + void endVisit(FieldReference fieldReference, BlockScope scope); + void endVisit(FloatLiteral floatLiteral, BlockScope scope); + void endVisit(ForStatement forStatement, BlockScope scope); + void endVisit(IfStatement ifStatement, BlockScope scope); + void endVisit(ImportReference importRef, CompilationUnitScope scope); + void endVisit(Initializer initializer, MethodScope scope); + void endVisit(InstanceOfExpression instanceOfExpression, BlockScope scope); + void endVisit(IntLiteral intLiteral, BlockScope scope); + void endVisit(LabeledStatement labeledStatement, BlockScope scope); + void endVisit(LocalDeclaration localDeclaration, BlockScope scope); + void endVisit(LocalTypeDeclaration localTypeDeclaration, BlockScope scope); + void endVisit(LongLiteral longLiteral, BlockScope scope); + void endVisit(MemberTypeDeclaration memberTypeDeclaration, ClassScope scope); + void endVisit(MessageSend messageSend, BlockScope scope); + void endVisit(MethodDeclaration methodDeclaration, ClassScope scope); + void endVisit(NullLiteral nullLiteral, BlockScope scope); + void endVisit(OR_OR_Expression or_or_Expression, BlockScope scope); + void endVisit(PostfixExpression postfixExpression, BlockScope scope); + void endVisit(PrefixExpression prefixExpression, BlockScope scope); + void endVisit(QualifiedAllocationExpression qualifiedAllocationExpression, BlockScope scope); + void endVisit(QualifiedNameReference qualifiedNameReference, BlockScope scope); + void endVisit(QualifiedSuperReference qualifiedSuperReference, BlockScope scope); + void endVisit(QualifiedThisReference qualifiedThisReference, BlockScope scope); + void endVisit(QualifiedTypeReference qualifiedTypeReference, BlockScope scope); + void endVisit(QualifiedTypeReference qualifiedTypeReference, ClassScope scope); + void endVisit(ReturnStatement returnStatement, BlockScope scope); + void endVisit(SingleNameReference singleNameReference, BlockScope scope); + void endVisit(SingleTypeReference singleTypeReference, BlockScope scope); + void endVisit(SingleTypeReference singleTypeReference, ClassScope scope); + void endVisit(StringLiteral stringLiteral, BlockScope scope); + void endVisit(SuperReference superReference, BlockScope scope); + void endVisit(SwitchStatement switchStatement, BlockScope scope); + void endVisit(SynchronizedStatement synchronizedStatement, BlockScope scope); + void endVisit(ThisReference thisReference, BlockScope scope); + void endVisit(ThrowStatement throwStatement, BlockScope scope); + void endVisit(TrueLiteral trueLiteral, BlockScope scope); + void endVisit(TryStatement tryStatement, BlockScope scope); + void endVisit(TypeDeclaration typeDeclaration, CompilationUnitScope scope); + void endVisit(UnaryExpression unaryExpression, BlockScope scope); + void endVisit(WhileStatement whileStatement, BlockScope scope); + boolean visit(AllocationExpression allocationExpression, BlockScope scope); + boolean visit(AND_AND_Expression and_and_Expression, BlockScope scope); + boolean visit(AnonymousLocalTypeDeclaration anonymousTypeDeclaration, BlockScope scope); + boolean visit(Argument argument, BlockScope scope); + boolean visit(ArrayAllocationExpression arrayAllocationExpression, BlockScope scope); + boolean visit(ArrayInitializer arrayInitializer, BlockScope scope); + boolean visit(ArrayQualifiedTypeReference arrayQualifiedTypeReference, BlockScope scope); + boolean visit(ArrayQualifiedTypeReference arrayQualifiedTypeReference, ClassScope scope); + boolean visit(ArrayReference arrayReference, BlockScope scope); + boolean visit(ArrayTypeReference arrayTypeReference, BlockScope scope); + boolean visit(ArrayTypeReference arrayTypeReference, ClassScope scope); + boolean visit(AssertStatement assertStatement, BlockScope scope); + boolean visit(Assignment assignment, BlockScope scope); + boolean visit(BinaryExpression binaryExpression, BlockScope scope); + boolean visit(Block block, BlockScope scope); + boolean visit(Break breakStatement, BlockScope scope); + boolean visit(Case caseStatement, BlockScope scope); + boolean visit(CastExpression castExpression, BlockScope scope); + boolean visit(CharLiteral charLiteral, BlockScope scope); + boolean visit(ClassLiteralAccess classLiteral, BlockScope scope); + boolean visit(Clinit clinit, ClassScope scope); + boolean visit(CompilationUnitDeclaration compilationUnitDeclaration, CompilationUnitScope scope); + boolean visit(CompoundAssignment compoundAssignment, BlockScope scope); + boolean visit(ConditionalExpression conditionalExpression, BlockScope scope); + boolean visit(ConstructorDeclaration constructorDeclaration, ClassScope scope); + boolean visit(Continue continueStatement, BlockScope scope); + boolean visit(DefaultCase defaultCaseStatement, BlockScope scope); + boolean visit(DoStatement doStatement, BlockScope scope); + boolean visit(DoubleLiteral doubleLiteral, BlockScope scope); + boolean visit(EqualExpression equalExpression, BlockScope scope); + boolean visit(EmptyStatement statement, BlockScope scope); + boolean visit(ExplicitConstructorCall explicitConstructor, BlockScope scope); + boolean visit(ExtendedStringLiteral extendedStringLiteral, BlockScope scope); + boolean visit(FalseLiteral falseLiteral, BlockScope scope); + boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope); + boolean visit(FieldReference fieldReference, BlockScope scope); + boolean visit(FloatLiteral floatLiteral, BlockScope scope); + boolean visit(ForStatement forStatement, BlockScope scope); + boolean visit(IfStatement ifStatement, BlockScope scope); + boolean visit(ImportReference importRef, CompilationUnitScope scope); + boolean visit(Initializer initializer, MethodScope scope); + boolean visit(InstanceOfExpression instanceOfExpression, BlockScope scope); + boolean visit(IntLiteral intLiteral, BlockScope scope); + boolean visit(LabeledStatement labeledStatement, BlockScope scope); + boolean visit(LocalDeclaration localDeclaration, BlockScope scope); + boolean visit(LocalTypeDeclaration localTypeDeclaration, BlockScope scope); + boolean visit(LongLiteral longLiteral, BlockScope scope); + boolean visit(MemberTypeDeclaration memberTypeDeclaration, ClassScope scope); + boolean visit(MessageSend messageSend, BlockScope scope); + boolean visit(MethodDeclaration methodDeclaration, ClassScope scope); + boolean visit(NullLiteral nullLiteral, BlockScope scope); + boolean visit(OR_OR_Expression or_or_Expression, BlockScope scope); + boolean visit(PostfixExpression postfixExpression, BlockScope scope); + boolean visit(PrefixExpression prefixExpression, BlockScope scope); + boolean visit(QualifiedAllocationExpression qualifiedAllocationExpression, BlockScope scope); + boolean visit(QualifiedNameReference qualifiedNameReference, BlockScope scope); + boolean visit(QualifiedSuperReference qualifiedSuperReference, BlockScope scope); + boolean visit(QualifiedThisReference qualifiedThisReference, BlockScope scope); + boolean visit(QualifiedTypeReference qualifiedTypeReference, BlockScope scope); + boolean visit(QualifiedTypeReference qualifiedTypeReference, ClassScope scope); + boolean visit(ReturnStatement returnStatement, BlockScope scope); + boolean visit(SingleNameReference singleNameReference, BlockScope scope); + boolean visit(SingleTypeReference singleTypeReference, BlockScope scope); + boolean visit(SingleTypeReference singleTypeReference, ClassScope scope); + boolean visit(StringLiteral stringLiteral, BlockScope scope); + boolean visit(SuperReference superReference, BlockScope scope); + boolean visit(SwitchStatement switchStatement, BlockScope scope); + boolean visit(SynchronizedStatement synchronizedStatement, BlockScope scope); + boolean visit(ThisReference thisReference, BlockScope scope); + boolean visit(ThrowStatement throwStatement, BlockScope scope); + boolean visit(TrueLiteral trueLiteral, BlockScope scope); + boolean visit(TryStatement tryStatement, BlockScope scope); + boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope); + boolean visit(UnaryExpression unaryExpression, BlockScope scope); + boolean visit(WhileStatement whileStatement, BlockScope scope); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ICompilerRequestor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ICompilerRequestor.java new file mode 100644 index 0000000..fca876b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ICompilerRequestor.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler; + +/** + * A callback interface for receiving compilation results. + */ +public interface ICompilerRequestor { + + /** + * Accept a compilation result. + */ + public void acceptResult(CompilationResult result); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/IDebugRequestor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/IDebugRequestor.java new file mode 100644 index 0000000..bd9ca5c --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/IDebugRequestor.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler; + +public interface IDebugRequestor { + + /* + * Debug callback method allowing to take into account a new compilation result. + * Any side-effect performed on the actual result might interfere with the + * original compiler requestor, and should be prohibited. + */ + void acceptDebugResult(CompilationResult result); + + /* + * Answers true when in active mode + */ + boolean isActive(); + + /* + * Activate debug callbacks + */ + void activate(); + + /* + * Deactivate debug callbacks + */ + void deactivate(); + + /* + * Reset debug requestor after compilation has finished + */ + void reset(); +} + diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/IDocumentElementRequestor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/IDocumentElementRequestor.java new file mode 100644 index 0000000..57e8e36 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/IDocumentElementRequestor.java @@ -0,0 +1,411 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler; + +import net.sourceforge.phpdt.core.compiler.IProblem; + +/** + * Part of the source element parser responsible for building the output. + * It gets notified of structural information as they are detected, relying + * on the requestor to assemble them together, based on the notifications it got. + * + * The structural investigation includes: + * - package statement + * - import statements + * - top-level types: package member, member types (member types of member types...) + * - fields + * - methods + * + * If reference information is requested, then all source constructs are + * investigated and type, field & method references are provided as well. + * + * Any (parsing) problem encountered is also provided. + * + * All positions are relative to the exact source fed to the parser. + * + * Elements which are complex are notified in two steps: + * - enter : once the element header has been identified + * - exit : once the element has been fully consumed + * + * other simpler elements (package, import) are read all at once: + * - accept + */ + +public interface IDocumentElementRequestor { +/** + * @param declarationStart - a source position corresponding to the start of the package + * declaration + * @param declarationEnd - a source position corresponding to the end of the package + * declaration + * @param javaDocPositions - answer back an array of sourceStart/sourceEnd + * positions of the available JavaDoc comments. The array is a flattened + * structure: 2*n entries with consecutives start and end positions. + * If no JavaDoc is available, then null is answered instead of an empty array. + * e.g. { 10, 20, 25, 45 } --> javadoc1 from 10 to 20, javadoc2 from 25 to 45 + * The array is equals to null if there are no javadoc comments + * @param name - the name of the package + * @param nameStartPosition - a source position corresponding to the first character of the + * name + * @param onDemand - a boolean equals to true if the import is an import on demand + */ +void acceptImport( + int declarationStart, + int declarationEnd, + int[] javaDocPositions, + char[] name, + int nameStartPosition, + boolean onDemand); +/** + * @param declarationStart - a source position corresponding to the start of the package + * declaration + * @param declarationEnd - a source position corresponding to the end of the package + * declaration + * @param javaDocPositions - answer back an array of sourceStart/sourceEnd + * positions of the available JavaDoc comments. The array is a flattened + * structure: 2*n entries with consecutives start and end positions. + * If no JavaDoc is available, then null is answered instead of an empty array. + * e.g. { 10, 20, 25, 45 } --> javadoc1 from 10 to 20, javadoc2 from 25 to 45 + * The array is equals to null if there are no javadoc comments + * @param modifiers - the modifiers for this initializer + * @param modifiersStart - a source position corresponding to the start + * of the textual modifiers, is < 0 if there are no textual modifiers + * @param bodyStart - the position of the '{' + * @param bodyEnd - the position of the '}' + */ +void acceptInitializer( + int declarationStart, + int declarationEnd, + int[] javaDocPositions, + int modifiers, + int modifiersStart, + int bodyStart, + int bodyEnd); +/* + * Table of line separator position. This table is passed once at the end + * of the parse action, so as to allow computation of normalized ranges. + * + * A line separator might corresponds to several characters in the source, + * + */ +void acceptLineSeparatorPositions(int[] positions); +/** + * @param declarationStart - a source position corresponding to the start of the package + * declaration + * @param declarationEnd - a source position corresponding to the end of the package + * declaration + * @param javaDocPositions - answer back an array of sourceStart/sourceEnd + * positions of the available JavaDoc comments. The array is a flattened + * structure: 2*n entries with consecutives start and end positions. + * If no JavaDoc is available, then null is answered instead of an empty array. + * e.g. { 10, 20, 25, 45 } --> javadoc1 from 10 to 20, javadoc2 from 25 to 45 + * The array is equals to null if there are no javadoc comments + * @param name - the name of the package + * @param nameStartPosition - a source position corresponding to the first character of the + * name + */ +void acceptPackage( + int declarationStart, + int declarationEnd, + int[] javaDocPositions, + char[] name, + int nameStartPosition); +/** + * @param problem - Used to report a problem while running the JDOM + */ +void acceptProblem(IProblem problem); +/** + * @param declarationStart - a source position corresponding to the start + * of this class. + * @param javaDocPositions - answer back an array of sourceStart/sourceEnd + * positions of the available JavaDoc comments. The array is a flattened + * structure: 2*n entries with consecutives start and end positions. + * If no JavaDoc is available, then null is answered instead of an empty array. + * e.g. { 10, 20, 25, 45 } --> javadoc1 from 10 to 20, javadoc2 from 25 to 45 + * The array is equals to null if there are no javadoc comments + * @param modifiers - the modifiers for this class + * @param modifiersStart - a source position corresponding to the start + * of the textual modifiers, is < 0 if there are no textual modifiers + * @param classStart - a source position corresponding to the start + * of the keyword 'class' + * @param name - the name of the class + * @param nameStart - a source position corresponding to the start of the name + * @param nameEnd - a source position corresponding to the end of the name + * @param superclass - the name of the superclass + * @param superclassStart - a source position corresponding to the start + * of the superclass name + * @param superclassEnd - a source position corresponding to the end of the + * superclass name + * @param superinterfaces - the name of the superinterfaces + * @param superinterfaceStarts - an array of source positions corresponding + * to the start of their respective superinterface names + * @param superinterfaceEnds - an array of source positions corresponding + * to the end of their respective superinterface names + * @param bodyStart - a source position corresponding to the open bracket + * of the class body + */ +void enterClass( + int declarationStart, + int[] javaDocPositions, + int modifiers, + int modifiersStart, + int classStart, + char[] name, + int nameStart, + int nameEnd, + char[] superclass, + int superclassStart, + int superclassEnd, + char[][] superinterfaces, + int[] superinterfaceStarts, + int[] superinterfaceEnds, + int bodyStart); +void enterCompilationUnit(); +/** + * @param declarationStart - a source position corresponding to the first character + * of this constructor declaration + * @param javaDocPositions - answer back an array of sourceStart/sourceEnd + * positions of the available JavaDoc comments. The array is a flattened + * structure: 2*n entries with consecutives start and end positions. + * If no JavaDoc is available, then null is answered instead of an empty array. + * e.g. { 10, 20, 25, 45 } --> javadoc1 from 10 to 20, javadoc2 from 25 to 45 + * The array is equals to null if there are no javadoc comments + * @param modifiers - the modifiers for this constructor converted to a flag + * @param modifiersStart - a source position corresponding to the first character of the + * textual modifiers + * @param name - the name of this constructor + * @param nameStart - a source position corresponding to the first character of the name + * @param nameEnd - a source position corresponding to the last character of the name + * @param parameterTypes - a list of parameter type names + * @param parameterTypeStarts - a list of source positions corresponding to the + * first character of each parameter type name + * @param parameterTypeEnds - a list of source positions corresponding to the + * last character of each parameter type name + * @param parameterNames - a list of the names of the parameters + * @param parametersEnd - a source position corresponding to the last character of the + * parameter list + * @param exceptionTypes - a list of the exception types + * @param exceptionTypeStarts - a list of source positions corresponding to the first + * character of the respective exception types + * @param exceptionTypeEnds - a list of source positions corresponding to the last + * character of the respective exception types + * @param bodyStart - a source position corresponding to the start of this + * constructor's body + */ +void enterConstructor( + int declarationStart, + int[] javaDocPositions, + int modifiers, + int modifiersStart, + char[] name, + int nameStart, + int nameEnd, + char[][] parameterTypes, + int [] parameterTypeStarts, + int [] parameterTypeEnds, + char[][] parameterNames, + int [] parameterNameStarts, + int [] parameterNameEnds, + int parametersEnd, + char[][] exceptionTypes, + int [] exceptionTypeStarts, + int [] exceptionTypeEnds, + int bodyStart); +/** + * @param declarationStart - a source position corresponding to the first character + * of this field + * @param javaDocPositions - answer back an array of sourceStart/sourceEnd + * positions of the available JavaDoc comments. The array is a flattened + * structure: 2*n entries with consecutives start and end positions. + * If no JavaDoc is available, then null is answered instead of an empty array. + * e.g. { 10, 20, 25, 45 } --> javadoc1 from 10 to 20, javadoc2 from 25 to 45 + * The array is equals to null if there are no javadoc comments + * @param modifiers - the modifiers for this field converted to a flag + * @param modifiersStart - a source position corresponding to the first character of the + * textual modifiers + * @param type - the name of the field type + * @param typeStart - a source position corresponding to the start of the fields type + * @param typeEnd - a source position corresponding to the end of the fields type + * @param typeDimensionCount - the array dimension indicated on the type, i.e. int[] v + * @param name - the name of this constructor + * @param nameStart - a source position corresponding to the first character of the name + * @param nameEnd - a source position corresponding to the last character of the name + * @param extendedTypeDimensionCount - the array dimension indicated on the variable, + * i.e. int v[] + * @param extendedTypeDimnesionEnd - a source position corresponding to the end of + * the extened type dimension. This position should be -1 in case there is no extended + * dimension for the type. + */ +void enterField( + int declarationStart, + int[] javaDocPositions, + int modifiers, + int modifiersStart, + char[] type, + int typeStart, + int typeEnd, + int typeDimensionCount, + char[] name, + int nameStart, + int nameEnd, + int extendedTypeDimensionCount, + int extendedTypeDimensionEnd); +/** + * @param declarationStart - a source position corresponding to the start + * of this class. + * @param javaDocPositions - answer back an array of sourceStart/sourceEnd + * positions of the available JavaDoc comments. The array is a flattened + * structure: 2*n entries with consecutives start and end positions. + * If no JavaDoc is available, then null is answered instead of an empty array. + * e.g. { 10, 20, 25, 45 } --> javadoc1 from 10 to 20, javadoc2 from 25 to 45 + * The array is equals to null if there are no javadoc comments + * @param modifiers - the modifiers for this class + * @param modifiersStart - a source position corresponding to the start + * of the textual modifiers, is < 0 if there are no textual modifiers + * @param interfaceStart - a source position corresponding to the start + * of the keyword 'interface' + * @param name - the name of the class + * @param nameStart - a source position corresponding to the start of the name + * @param nameEnd - a source position corresponding to the end of the name + * @param superinterfaces - the name of the superinterfaces + * @param superinterfaceStarts - an array of source positions corresponding + * to the start of their respective superinterface names + * @param superinterfaceEnds - an array of source positions corresponding + * to the end of their respective superinterface names + * @param bodyStart - a source position corresponding to the open bracket + * of the class body + */ +void enterInterface( + int declarationStart, + int[] javaDocPositions, + int modifiers, + int modifiersStart, + int interfaceStart, + char[] name, + int nameStart, + int nameEnd, + char[][] superinterfaces, + int[] superinterfaceStarts, + int[] superinterfaceEnds, + int bodyStart); +/** + * @param declarationStart - a source position corresponding to the first character + * of this constructor declaration + * @param javaDocPositions - answer back an array of sourceStart/sourceEnd + * positions of the available JavaDoc comments. The array is a flattened + * structure: 2*n entries with consecutives start and end positions. + * If no JavaDoc is available, then null is answered instead of an empty array. + * e.g. { 10, 20, 25, 45 } --> javadoc1 from 10 to 20, javadoc2 from 25 to 45 + * The array is equals to null if there are no javadoc comments + * @param modifiers - the modifiers for this constructor converted to a flag + * @param modifiersStart - a source position corresponding to the first character of the + * textual modifiers + * @param returnType - the name of the return type + * @param returnTypeStart - a source position corresponding to the first character + * of the return type + * @param returnTypeEnd - a source position corresponding to the last character + * of the return type + * @param returnTypeDimensionCount - the array dimension count as supplied on the + * return type, i.e. public int[] foo() {} + * @param name - the name of this constructor + * @param nameStart - a source position corresponding to the first character of the name + * @param nameEnd - a source position corresponding to the last character of the name + * @param parameterTypes - a list of parameter type names + * @param parameterTypeStarts - a list of source positions corresponding to the + * first character of each parameter type name + * @param parameterTypeEnds - a list of source positions corresponding to the + * last character of each parameter type name + * @param parameterNames - a list of the names of the parameters + * @param parametersEnd - a source position corresponding to the last character of the + * parameter list + * @param extendedReturnTypeDimensionCount - the array dimension count as supplied on the + * end of the parameter list, i.e. public int foo()[] {} + * @param extendedReturnTypeDimensionEnd - a source position corresponding to the last character + * of the extended return type dimension. This position should be -1 in case there is no extended + * dimension for the type. + * @param exceptionTypes - a list of the exception types + * @param exceptionTypeStarts - a list of source positions corresponding to the first + * character of the respective exception types + * @param exceptionTypeEnds - a list of source positions corresponding to the last + * character of the respective exception types + * @param bodyStart - a source position corresponding to the start of this + * method's body + */ +void enterMethod( + int declarationStart, + int[] javaDocPositions, + int modifiers, + int modifiersStart, + char[] returnType, + int returnTypeStart, + int returnTypeEnd, + int returnTypeDimensionCount, + char[] name, + int nameStart, + int nameEnd, + char[][] parameterTypes, + int [] parameterTypeStarts, + int [] parameterTypeEnds, + char[][] parameterNames, + int [] parameterNameStarts, + int [] parameterNameEnds, + int parametersEnd, + int extendedReturnTypeDimensionCount, + int extendedReturnTypeDimensionEnd, + char[][] exceptionTypes, + int [] exceptionTypeStarts, + int [] exceptionTypeEnds, + int bodyStart); +/** + * @param bodyEnd - a source position corresponding to the closing bracket of the class + * @param declarationEnd - a source position corresponding to the end of the class + * declaration. This can include whitespace and comments following the closing bracket. + */ +void exitClass( + int bodyEnd, + int declarationEnd); +/** + * @param declarationEnd - a source position corresponding to the end of the compilation unit + */ +void exitCompilationUnit( + int declarationEnd); +/** + * @param bodyEnd - a source position corresponding to the closing bracket of the method + * @param declarationEnd - a source position corresponding to the end of the method + * declaration. This can include whitespace and comments following the closing bracket. + */ +void exitConstructor( + int bodyEnd, + int declarationEnd); +/** + * @param bodyEnd - a source position corresponding to the end of the field. + * @param declarationEnd - a source position corresponding to the end of the field. + * This can include whitespace and comments following the semi-colon. + */ +void exitField( + int bodyEnd, + int declarationEnd); +/** + * @param bodyEnd - a source position corresponding to the closing bracket of the interface + * @param declarationEnd - a source position corresponding to the end of the interface + * declaration. This can include whitespace and comments following the closing bracket. + */ +void exitInterface( + int bodyEnd, + int declarationEnd); +/** + * @param bodyEnd - a source position corresponding to the closing bracket of the method + * @param declarationEnd - a source position corresponding to the end of the method + * declaration. This can include whitespace and comments following the closing bracket. + */ +void exitMethod( + int bodyEnd, + int declarationEnd); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/IErrorHandlingPolicy.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/IErrorHandlingPolicy.java new file mode 100644 index 0000000..5231bae --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/IErrorHandlingPolicy.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler; + +/* + * Handler policy is responsible to answer the 2 following + * questions: + * 1. should the handler stop on first problem which appears + * to be a real error (i.e. not a warning), + * 2. should it proceed once it has gathered all problems + * + * The intent is that one can supply its own policy to implement + * some interactive error handling strategy where some UI would + * display problems and ask user if he wants to proceed or not. + */ + +public interface IErrorHandlingPolicy { + boolean proceedOnErrors(); + boolean stopOnFirstError(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/IProblemFactory.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/IProblemFactory.java new file mode 100644 index 0000000..7d91113 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/IProblemFactory.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler; + +import java.util.Locale; + +import net.sourceforge.phpdt.core.compiler.*; + +/* + * Factory used from inside the compiler to build the actual problems + * which are handed back in the compilation result. + * + * This allows sharing the internal problem representation with the environment. + * + * Note: The factory is responsible for computing and storing a localized error message. + */ + +public interface IProblemFactory { + + IProblem createProblem( + char[] originatingFileName, + int problemId, + String[] arguments, + int severity, + int startPosition, + int endPosition, + int lineNumber); + + Locale getLocale(); + + String getLocalizedMessage(int problemId, String[] problemArguments); +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ISourceElementRequestor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ISourceElementRequestor.java new file mode 100644 index 0000000..80cfd7c --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ISourceElementRequestor.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler; + +import net.sourceforge.phpdt.core.compiler.IProblem; + +/* + * Part of the source element parser responsible for building the output. + * It gets notified of structural information as they are detected, relying + * on the requestor to assemble them together, based on the notifications it got. + * + * The structural investigation includes: + * - package statement + * - import statements + * - top-level types: package member, member types (member types of member types...) + * - fields + * - methods + * + * If reference information is requested, then all source constructs are + * investigated and type, field & method references are provided as well. + * + * Any (parsing) problem encountered is also provided. + * + * All positions are relative to the exact source fed to the parser. + * + * Elements which are complex are notified in two steps: + * - enter : once the element header has been identified + * - exit : once the element has been fully consumed + * + * other simpler elements (package, import) are read all at once: + * - accept + */ + +public interface ISourceElementRequestor { +void acceptConstructorReference(char[] typeName, int argCount, int sourcePosition); +void acceptFieldReference(char[] fieldName, int sourcePosition); +/** + * @param declarationStart This is the position of the first character of the + * import keyword. + * @param declarationEnd This is the position of the ';' ending the import statement + * or the end of the comment following the import. + * @param name This is the name of the import like specified in the source including the dots. The '.*' + * is never included in the name. + * @param onDemand set to true if the import is an import on demand (e.g. import java.io.*). False otherwise. + */ +void acceptImport( + int declarationStart, + int declarationEnd, + char[] name, + boolean onDemand); +/* + * Table of line separator position. This table is passed once at the end + * of the parse action, so as to allow computation of normalized ranges. + * + * A line separator might corresponds to several characters in the source, + * + */ +void acceptLineSeparatorPositions(int[] positions); +void acceptMethodReference(char[] methodName, int argCount, int sourcePosition); +void acceptPackage( + int declarationStart, + int declarationEnd, + char[] name); +void acceptProblem(IProblem problem); +void acceptTypeReference(char[][] typeName, int sourceStart, int sourceEnd); +void acceptTypeReference(char[] typeName, int sourcePosition); +void acceptUnknownReference(char[][] name, int sourceStart, int sourceEnd); +void acceptUnknownReference(char[] name, int sourcePosition); +void enterClass( + int declarationStart, + int modifiers, + char[] name, + int nameSourceStart, + int nameSourceEnd, + char[] superclass, + char[][] superinterfaces); +void enterCompilationUnit(); +void enterConstructor( + int declarationStart, + int modifiers, + char[] name, + int nameSourceStart, + int nameSourceEnd, + char[][] parameterTypes, + char[][] parameterNames, + char[][] exceptionTypes); +void enterField( + int declarationStart, + int modifiers, + char[] type, + char[] name, + int nameSourceStart, + int nameSourceEnd); +void enterInitializer( + int declarationStart, + int modifiers); +void enterInterface( + int declarationStart, + int modifiers, + char[] name, + int nameSourceStart, + int nameSourceEnd, + char[][] superinterfaces); +void enterMethod( + int declarationStart, + int modifiers, + char[] returnType, + char[] name, + int nameSourceStart, + int nameSourceEnd, + char[][] parameterTypes, + char[][] parameterNames, + char[][] exceptionTypes); +void exitClass(int declarationEnd); +void exitCompilationUnit(int declarationEnd); +void exitConstructor(int declarationEnd); +/* + * - No initialization source for now - + * initializationSource denotes the source of the expression used for initializing + * the field if any (if no source, then it is null). + * + * Note: the initializationSource will be used in case we do need to type check + * against source models, and thus the only interesting use for it is field + * constant propagation. Therefore, the initializationSource will only be non + * null for final fields (so as to minimize char[] allocations). + */ +void exitField(/*char[] initializationSource, */int declarationEnd); +void exitInitializer(int declarationEnd); +void exitInterface(int declarationEnd); +void exitMethod(int declarationEnd); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/SourceElementParser.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/SourceElementParser.java new file mode 100644 index 0000000..9c346d5 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/SourceElementParser.java @@ -0,0 +1,1294 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler; + +/** + * A source element parser extracts structural and reference information + * from a piece of source. + * + * also see @ISourceElementRequestor + * + * The structural investigation includes: + * - the package statement + * - import statements + * - top-level types: package member, member types (member types of member types...) + * - fields + * - methods + * + * If reference information is requested, then all source constructs are + * investigated and type, field & method references are provided as well. + * + * Any (parsing) problem encountered is also provided. + */ + +import net.sourceforge.phpdt.internal.compiler.env.*; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.core.compiler.*; +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.parser.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; +import net.sourceforge.phpdt.internal.compiler.util.*; + +public class SourceElementParser extends Parser { + + ISourceElementRequestor requestor; + private int fieldCount; + private int localIntPtr; + private int lastFieldEndPosition; + private ISourceType sourceType; + private boolean reportReferenceInfo; + private char[][] typeNames; + private char[][] superTypeNames; + private int nestedTypeIndex; + private static final char[] JAVA_LANG_OBJECT = "java.lang.Object".toCharArray(); //$NON-NLS-1$ + private NameReference[] unknownRefs; + private int unknownRefsCounter; + private LocalDeclarationVisitor localDeclarationVisitor = null; + private CompilerOptions options; + +/** + * An ast visitor that visits local type declarations. + */ +public class LocalDeclarationVisitor extends AbstractSyntaxTreeVisitorAdapter { + public boolean visit( + AnonymousLocalTypeDeclaration anonymousTypeDeclaration, + BlockScope scope) { + notifySourceElementRequestor(anonymousTypeDeclaration, sourceType == null); + return false; // don't visit members as this was done during notifySourceElementRequestor(...) + } + public boolean visit(LocalTypeDeclaration typeDeclaration, BlockScope scope) { + notifySourceElementRequestor(typeDeclaration, sourceType == null); + return false; // don't visit members as this was done during notifySourceElementRequestor(...) + } + public boolean visit(MemberTypeDeclaration typeDeclaration, ClassScope scope) { + notifySourceElementRequestor(typeDeclaration, sourceType == null); + return false; // don't visit members as this was done during notifySourceElementRequestor(...) + } + +} + +public SourceElementParser( + final ISourceElementRequestor requestor, + IProblemFactory problemFactory, + CompilerOptions options) { + // we want to notify all syntax error with the acceptProblem API + // To do so, we define the record method of the ProblemReporter + super(new ProblemReporter( + DefaultErrorHandlingPolicies.exitAfterAllProblems(), + options, + problemFactory) { + public void record(IProblem problem, CompilationResult unitResult, ReferenceContext referenceContext) { + unitResult.record(problem, referenceContext); + requestor.acceptProblem(problem); + } + }, + true, + options.assertMode); + this.requestor = requestor; + typeNames = new char[4][]; + superTypeNames = new char[4][]; + nestedTypeIndex = 0; + this.options = options; +} + +/** @deprecated use SourceElementParser(ISourceElementRequestor, IProblemFactory, CompilerOptions) */ +public SourceElementParser( + final ISourceElementRequestor requestor, + IProblemFactory problemFactory) { + this(requestor, problemFactory, new CompilerOptions()); +} + +public SourceElementParser( + final ISourceElementRequestor requestor, + IProblemFactory problemFactory, + CompilerOptions options, + boolean reportLocalDeclarations) { + this(requestor, problemFactory, options); + if (reportLocalDeclarations) { + this.localDeclarationVisitor = new LocalDeclarationVisitor(); + } +} + +public void checkAnnotation() { + int firstCommentIndex = scanner.commentPtr; + + super.checkAnnotation(); + + // modify the modifier source start to point at the first comment + if (firstCommentIndex >= 0) { + modifiersSourceStart = scanner.commentStarts[0]; + } +} + +protected void classInstanceCreation(boolean alwaysQualified) { + + boolean previousFlag = reportReferenceInfo; + reportReferenceInfo = false; // not to see the type reference reported in super call to getTypeReference(...) + super.classInstanceCreation(alwaysQualified); + reportReferenceInfo = previousFlag; + if (reportReferenceInfo){ + AllocationExpression alloc = (AllocationExpression)expressionStack[expressionPtr]; + TypeReference typeRef = alloc.type; + requestor.acceptConstructorReference( + typeRef instanceof SingleTypeReference + ? ((SingleTypeReference) typeRef).token + : CharOperation.concatWith(alloc.type.getTypeName(), '.'), + alloc.arguments == null ? 0 : alloc.arguments.length, + alloc.sourceStart); + } +} +protected void consumeConstructorHeaderName() { + // ConstructorHeaderName ::= Modifiersopt 'Identifier' '(' + + /* recovering - might be an empty message send */ + if (currentElement != null){ + if (lastIgnoredToken == TokenNamenew){ // was an allocation expression + lastCheckPoint = scanner.startPosition; // force to restart at this exact position + restartRecovery = true; + return; + } + } + SourceConstructorDeclaration cd = new SourceConstructorDeclaration(this.compilationUnit.compilationResult); + + //name -- this is not really revelant but we do ..... + cd.selector = identifierStack[identifierPtr]; + long selectorSourcePositions = identifierPositionStack[identifierPtr--]; + identifierLengthPtr--; + + //modifiers + cd.declarationSourceStart = intStack[intPtr--]; + cd.modifiers = intStack[intPtr--]; + + //highlight starts at the selector starts + cd.sourceStart = (int) (selectorSourcePositions >>> 32); + cd.selectorSourceEnd = (int) selectorSourcePositions; + pushOnAstStack(cd); + + cd.sourceEnd = lParenPos; + cd.bodyStart = lParenPos+1; + listLength = 0; // initialize listLength before reading parameters/throws + + // recovery + if (currentElement != null){ + lastCheckPoint = cd.bodyStart; + if ((currentElement instanceof RecoveredType && lastIgnoredToken != TokenNameDOT) + || cd.modifiers != 0){ + currentElement = currentElement.add(cd, 0); + lastIgnoredToken = -1; + } + } +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeExitVariableWithInitialization() { + // ExitVariableWithInitialization ::= $empty + // the scanner is located after the comma or the semi-colon. + // we want to include the comma or the semi-colon + super.consumeExitVariableWithInitialization(); + if (isLocalDeclaration() || ((currentToken != TokenNameCOMMA) && (currentToken != TokenNameSEMICOLON))) + return; + ((SourceFieldDeclaration) astStack[astPtr]).fieldEndPosition = scanner.currentPosition - 1; +} +protected void consumeExitVariableWithoutInitialization() { + // ExitVariableWithoutInitialization ::= $empty + // do nothing by default + if (isLocalDeclaration() || ((currentToken != TokenNameCOMMA) && (currentToken != TokenNameSEMICOLON))) + return; + ((SourceFieldDeclaration) astStack[astPtr]).fieldEndPosition = scanner.currentPosition - 1; +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeFieldAccess(boolean isSuperAccess) { + // FieldAccess ::= Primary '.' 'Identifier' + // FieldAccess ::= 'super' '.' 'Identifier' + super.consumeFieldAccess(isSuperAccess); + FieldReference fr = (FieldReference) expressionStack[expressionPtr]; + if (reportReferenceInfo) { + requestor.acceptFieldReference(fr.token, fr.sourceStart); + } +} +protected void consumeMethodHeaderName() { + // MethodHeaderName ::= Modifiersopt Type 'Identifier' '(' + SourceMethodDeclaration md = new SourceMethodDeclaration(this.compilationUnit.compilationResult); + + //name + md.selector = identifierStack[identifierPtr]; + long selectorSourcePositions = identifierPositionStack[identifierPtr--]; + identifierLengthPtr--; + //type + md.returnType = getTypeReference(intStack[intPtr--]); + //modifiers + md.declarationSourceStart = intStack[intPtr--]; + md.modifiers = intStack[intPtr--]; + + //highlight starts at selector start + md.sourceStart = (int) (selectorSourcePositions >>> 32); + md.selectorSourceEnd = (int) selectorSourcePositions; + pushOnAstStack(md); + md.sourceEnd = lParenPos; + md.bodyStart = lParenPos+1; + listLength = 0; // initialize listLength before reading parameters/throws + + // recovery + if (currentElement != null){ + if (currentElement instanceof RecoveredType + //|| md.modifiers != 0 + || (scanner.getLineNumber(md.returnType.sourceStart) + == scanner.getLineNumber(md.sourceStart))){ + lastCheckPoint = md.bodyStart; + currentElement = currentElement.add(md, 0); + lastIgnoredToken = -1; + } else { + lastCheckPoint = md.sourceStart; + restartRecovery = true; + } + } +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeMethodInvocationName() { + // MethodInvocation ::= Name '(' ArgumentListopt ')' + + // when the name is only an identifier...we have a message send to "this" (implicit) + super.consumeMethodInvocationName(); + MessageSend messageSend = (MessageSend) expressionStack[expressionPtr]; + Expression[] args = messageSend.arguments; + if (reportReferenceInfo) { + requestor.acceptMethodReference( + messageSend.selector, + args == null ? 0 : args.length, + (int)(messageSend.nameSourcePosition >>> 32)); + } +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeMethodInvocationPrimary() { + super.consumeMethodInvocationPrimary(); + MessageSend messageSend = (MessageSend) expressionStack[expressionPtr]; + Expression[] args = messageSend.arguments; + if (reportReferenceInfo) { + requestor.acceptMethodReference( + messageSend.selector, + args == null ? 0 : args.length, + (int)(messageSend.nameSourcePosition >>> 32)); + } +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeMethodInvocationSuper() { + // MethodInvocation ::= 'super' '.' 'Identifier' '(' ArgumentListopt ')' + super.consumeMethodInvocationSuper(); + MessageSend messageSend = (MessageSend) expressionStack[expressionPtr]; + Expression[] args = messageSend.arguments; + if (reportReferenceInfo) { + requestor.acceptMethodReference( + messageSend.selector, + args == null ? 0 : args.length, + (int)(messageSend.nameSourcePosition >>> 32)); + } +} +protected void consumeSingleTypeImportDeclarationName() { + // SingleTypeImportDeclarationName ::= 'import' Name + /* push an ImportRef build from the last name + stored in the identifier stack. */ + + super.consumeSingleTypeImportDeclarationName(); + ImportReference impt = (ImportReference)astStack[astPtr]; + if (reportReferenceInfo) { + requestor.acceptTypeReference(impt.tokens, impt.sourceStart, impt.sourceEnd); + } +} +protected void consumeTypeImportOnDemandDeclarationName() { + // TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*' + /* push an ImportRef build from the last name + stored in the identifier stack. */ + + super.consumeTypeImportOnDemandDeclarationName(); + ImportReference impt = (ImportReference)astStack[astPtr]; + if (reportReferenceInfo) { + requestor.acceptUnknownReference(impt.tokens, impt.sourceStart, impt.sourceEnd); + } +} +protected FieldDeclaration createFieldDeclaration(Expression initialization, char[] name, int sourceStart, int sourceEnd) { + return new SourceFieldDeclaration(null, name, sourceStart, sourceEnd); +} +protected CompilationUnitDeclaration endParse(int act) { + if (sourceType != null) { + if (sourceType.isInterface()) { + consumeInterfaceDeclaration(); + } else { + consumeClassDeclaration(); + } + } + if (compilationUnit != null) { + CompilationUnitDeclaration result = super.endParse(act); + return result; + } else { + return null; + } +} +/* + * Flush annotations defined prior to a given positions. + * + * Note: annotations are stacked in syntactical order + * + * Either answer given , or the end position of a comment line + * immediately following the (same line) + * + * e.g. + * void foo(){ + * } // end of method foo + */ + +public int flushAnnotationsDefinedPriorTo(int position) { + + return lastFieldEndPosition = super.flushAnnotationsDefinedPriorTo(position); +} +public TypeReference getTypeReference(int dim) { + /* build a Reference on a variable that may be qualified or not + * This variable is a type reference and dim will be its dimensions + */ + int length; + if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) { + // single variable reference + if (dim == 0) { + SingleTypeReference ref = + new SingleTypeReference( + identifierStack[identifierPtr], + identifierPositionStack[identifierPtr--]); + if (reportReferenceInfo) { + requestor.acceptTypeReference(ref.token, ref.sourceStart); + } + return ref; + } else { + ArrayTypeReference ref = + new ArrayTypeReference( + identifierStack[identifierPtr], + dim, + identifierPositionStack[identifierPtr--]); + ref.sourceEnd = endPosition; + if (reportReferenceInfo) { + requestor.acceptTypeReference(ref.token, ref.sourceStart); + } + return ref; + } + } else { + if (length < 0) { //flag for precompiled type reference on base types + TypeReference ref = TypeReference.baseTypeReference(-length, dim); + ref.sourceStart = intStack[intPtr--]; + if (dim == 0) { + ref.sourceEnd = intStack[intPtr--]; + } else { + intPtr--; // no need to use this position as it is an array + ref.sourceEnd = endPosition; + } + if (reportReferenceInfo){ + requestor.acceptTypeReference(ref.getTypeName(), ref.sourceStart, ref.sourceEnd); + } + return ref; + } else { //Qualified variable reference + char[][] tokens = new char[length][]; + identifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length); + System.arraycopy( + identifierPositionStack, + identifierPtr + 1, + positions, + 0, + length); + if (dim == 0) { + QualifiedTypeReference ref = new QualifiedTypeReference(tokens, positions); + if (reportReferenceInfo) { + requestor.acceptTypeReference(ref.tokens, ref.sourceStart, ref.sourceEnd); + } + return ref; + } else { + ArrayQualifiedTypeReference ref = + new ArrayQualifiedTypeReference(tokens, dim, positions); + ref.sourceEnd = endPosition; + if (reportReferenceInfo) { + requestor.acceptTypeReference(ref.tokens, ref.sourceStart, ref.sourceEnd); + } + return ref; + } + } + } +} +public NameReference getUnspecifiedReference() { + /* build a (unspecified) NameReference which may be qualified*/ + + int length; + if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) { + // single variable reference + SingleNameReference ref = + new SingleNameReference( + identifierStack[identifierPtr], + identifierPositionStack[identifierPtr--]); + if (reportReferenceInfo) { + this.addUnknownRef(ref); + } + return ref; + } else { + //Qualified variable reference + char[][] tokens = new char[length][]; + identifierPtr -= length; + System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length); + QualifiedNameReference ref = + new QualifiedNameReference( + tokens, + (int) (identifierPositionStack[identifierPtr + 1] >> 32), // sourceStart + (int) identifierPositionStack[identifierPtr + length]); // sourceEnd + if (reportReferenceInfo) { + this.addUnknownRef(ref); + } + return ref; + } +} +public NameReference getUnspecifiedReferenceOptimized() { + /* build a (unspecified) NameReference which may be qualified + The optimization occurs for qualified reference while we are + certain in this case the last item of the qualified name is + a field access. This optimization is IMPORTANT while it results + that when a NameReference is build, the type checker should always + look for that it is not a type reference */ + + int length; + if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) { + // single variable reference + SingleNameReference ref = + new SingleNameReference( + identifierStack[identifierPtr], + identifierPositionStack[identifierPtr--]); + ref.bits &= ~AstNode.RestrictiveFlagMASK; + ref.bits |= LOCAL | FIELD; + if (reportReferenceInfo) { + this.addUnknownRef(ref); + } + return ref; + } + + //Qualified-variable-reference + //In fact it is variable-reference DOT field-ref , but it would result in a type + //conflict tha can be only reduce by making a superclass (or inetrface ) between + //nameReference and FiledReference or putting FieldReference under NameReference + //or else..........This optimisation is not really relevant so just leave as it is + + char[][] tokens = new char[length][]; + identifierPtr -= length; + System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length); + QualifiedNameReference ref = + new QualifiedNameReference( + tokens, + (int) (identifierPositionStack[identifierPtr + 1] >> 32), + // sourceStart + (int) identifierPositionStack[identifierPtr + length]); // sourceEnd + ref.bits &= ~AstNode.RestrictiveFlagMASK; + ref.bits |= LOCAL | FIELD; + if (reportReferenceInfo) { + this.addUnknownRef(ref); + } + return ref; +} +/** + * + * INTERNAL USE-ONLY + */ +private boolean isLocalDeclaration() { + int nestedDepth = nestedType; + while (nestedDepth >= 0) { + if (nestedMethod[nestedDepth] != 0) { + return true; + } + nestedDepth--; + } + return false; +} +/* + * Update the bodyStart of the corresponding parse node + */ +public void notifySourceElementRequestor(CompilationUnitDeclaration parsedUnit) { + if (parsedUnit == null) { + // when we parse a single type member declaration the compilation unit is null, but we still + // want to be able to notify the requestor on the created ast node + if (astStack[0] instanceof AbstractMethodDeclaration) { + notifySourceElementRequestor((AbstractMethodDeclaration) astStack[0]); + return; + } + return; + } + // range check + boolean isInRange = + scanner.initialPosition <= parsedUnit.sourceStart + && scanner.eofPosition >= parsedUnit.sourceEnd; + + if (reportReferenceInfo) { + notifyAllUnknownReferences(); + } + // collect the top level ast nodes + int length = 0; + AstNode[] nodes = null; + if (sourceType == null){ + if (isInRange) { + requestor.enterCompilationUnit(); + } + ImportReference currentPackage = parsedUnit.currentPackage; + ImportReference[] imports = parsedUnit.imports; + TypeDeclaration[] types = parsedUnit.types; + length = + (currentPackage == null ? 0 : 1) + + (imports == null ? 0 : imports.length) + + (types == null ? 0 : types.length); + nodes = new AstNode[length]; + int index = 0; + if (currentPackage != null) { + nodes[index++] = currentPackage; + } + if (imports != null) { + for (int i = 0, max = imports.length; i < max; i++) { + nodes[index++] = imports[i]; + } + } + if (types != null) { + for (int i = 0, max = types.length; i < max; i++) { + nodes[index++] = types[i]; + } + } + } else { + TypeDeclaration[] types = parsedUnit.types; + if (types != null) { + length = types.length; + nodes = new AstNode[length]; + for (int i = 0, max = types.length; i < max; i++) { + nodes[i] = types[i]; + } + } + } + + // notify the nodes in the syntactical order + if (nodes != null && length > 0) { + quickSort(nodes, 0, length-1); + for (int i=0;i= methodDeclaration.declarationSourceEnd; + + if (methodDeclaration.isClinit()) { + this.visitIfNeeded(methodDeclaration); + return; + } + + if (methodDeclaration.isDefaultConstructor()) { + if (reportReferenceInfo) { + ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) methodDeclaration; + ExplicitConstructorCall constructorCall = constructorDeclaration.constructorCall; + if (constructorCall != null) { + switch(constructorCall.accessMode) { + case ExplicitConstructorCall.This : + requestor.acceptConstructorReference( + typeNames[nestedTypeIndex-1], + constructorCall.arguments == null ? 0 : constructorCall.arguments.length, + constructorCall.sourceStart); + break; + case ExplicitConstructorCall.Super : + case ExplicitConstructorCall.ImplicitSuper : + requestor.acceptConstructorReference( + superTypeNames[nestedTypeIndex-1], + constructorCall.arguments == null ? 0 : constructorCall.arguments.length, + constructorCall.sourceStart); + break; + } + } + } + return; + } + char[][] argumentTypes = null; + char[][] argumentNames = null; + Argument[] arguments = methodDeclaration.arguments; + if (arguments != null) { + int argumentLength = arguments.length; + argumentTypes = new char[argumentLength][]; + argumentNames = new char[argumentLength][]; + for (int i = 0; i < argumentLength; i++) { + argumentTypes[i] = returnTypeName(arguments[i].type); + argumentNames[i] = arguments[i].name; + } + } + char[][] thrownExceptionTypes = null; + TypeReference[] thrownExceptions = methodDeclaration.thrownExceptions; + if (thrownExceptions != null) { + int thrownExceptionLength = thrownExceptions.length; + thrownExceptionTypes = new char[thrownExceptionLength][]; + for (int i = 0; i < thrownExceptionLength; i++) { + thrownExceptionTypes[i] = + CharOperation.concatWith(thrownExceptions[i].getTypeName(), '.'); + } + } + // by default no selector end position + int selectorSourceEnd = -1; + if (methodDeclaration.isConstructor()) { + if (methodDeclaration instanceof SourceConstructorDeclaration) { + selectorSourceEnd = + ((SourceConstructorDeclaration) methodDeclaration).selectorSourceEnd; + } + if (isInRange){ + requestor.enterConstructor( + methodDeclaration.declarationSourceStart, + methodDeclaration.modifiers, + methodDeclaration.selector, + methodDeclaration.sourceStart, + selectorSourceEnd, + argumentTypes, + argumentNames, + thrownExceptionTypes); + } + if (reportReferenceInfo) { + ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) methodDeclaration; + ExplicitConstructorCall constructorCall = constructorDeclaration.constructorCall; + if (constructorCall != null) { + switch(constructorCall.accessMode) { + case ExplicitConstructorCall.This : + requestor.acceptConstructorReference( + typeNames[nestedTypeIndex-1], + constructorCall.arguments == null ? 0 : constructorCall.arguments.length, + constructorCall.sourceStart); + break; + case ExplicitConstructorCall.Super : + case ExplicitConstructorCall.ImplicitSuper : + requestor.acceptConstructorReference( + superTypeNames[nestedTypeIndex-1], + constructorCall.arguments == null ? 0 : constructorCall.arguments.length, + constructorCall.sourceStart); + break; + } + } + } + this.visitIfNeeded(methodDeclaration); + if (isInRange){ + requestor.exitConstructor(methodDeclaration.declarationSourceEnd); + } + return; + } + if (methodDeclaration instanceof SourceMethodDeclaration) { + selectorSourceEnd = + ((SourceMethodDeclaration) methodDeclaration).selectorSourceEnd; + } + if (isInRange){ + requestor.enterMethod( + methodDeclaration.declarationSourceStart, + methodDeclaration.modifiers & AccJustFlag, + returnTypeName(((MethodDeclaration) methodDeclaration).returnType), + methodDeclaration.selector, + methodDeclaration.sourceStart, + selectorSourceEnd, + argumentTypes, + argumentNames, + thrownExceptionTypes); + } + this.visitIfNeeded(methodDeclaration); + + if (isInRange){ + requestor.exitMethod(methodDeclaration.declarationSourceEnd); + } +} +/* +* Update the bodyStart of the corresponding parse node +*/ +public void notifySourceElementRequestor(FieldDeclaration fieldDeclaration) { + + // range check + boolean isInRange = + scanner.initialPosition <= fieldDeclaration.declarationSourceStart + && scanner.eofPosition >= fieldDeclaration.declarationSourceEnd; + + if (fieldDeclaration.isField()) { + int fieldEndPosition = fieldDeclaration.declarationSourceEnd; + if (fieldDeclaration instanceof SourceFieldDeclaration) { + fieldEndPosition = ((SourceFieldDeclaration) fieldDeclaration).fieldEndPosition; + if (fieldEndPosition == 0) { + // use the declaration source end by default + fieldEndPosition = fieldDeclaration.declarationSourceEnd; + } + } + if (isInRange) { + requestor.enterField( + fieldDeclaration.declarationSourceStart, + fieldDeclaration.modifiers & AccJustFlag, + returnTypeName(fieldDeclaration.type), + fieldDeclaration.name, + fieldDeclaration.sourceStart, + fieldDeclaration.sourceEnd); + } + this.visitIfNeeded(fieldDeclaration); + if (isInRange){ + requestor.exitField(fieldEndPosition); + } + + } else { + if (isInRange){ + requestor.enterInitializer( + fieldDeclaration.declarationSourceStart, + fieldDeclaration.modifiers); + } + this.visitIfNeeded((Initializer)fieldDeclaration); + if (isInRange){ + requestor.exitInitializer(fieldDeclaration.declarationSourceEnd); + } + } +} +public void notifySourceElementRequestor( + ImportReference importReference, + boolean isPackage) { + if (isPackage) { + requestor.acceptPackage( + importReference.declarationSourceStart, + importReference.declarationSourceEnd, + CharOperation.concatWith(importReference.getImportName(), '.')); + } else { + requestor.acceptImport( + importReference.declarationSourceStart, + importReference.declarationSourceEnd, + CharOperation.concatWith(importReference.getImportName(), '.'), + importReference.onDemand); + } +} +public void notifySourceElementRequestor(TypeDeclaration typeDeclaration, boolean notifyTypePresence) { + + // range check + boolean isInRange = + scanner.initialPosition <= typeDeclaration.declarationSourceStart + && scanner.eofPosition >= typeDeclaration.declarationSourceEnd; + + FieldDeclaration[] fields = typeDeclaration.fields; + AbstractMethodDeclaration[] methods = typeDeclaration.methods; + MemberTypeDeclaration[] memberTypes = typeDeclaration.memberTypes; + int fieldCount = fields == null ? 0 : fields.length; + int methodCount = methods == null ? 0 : methods.length; + int memberTypeCount = memberTypes == null ? 0 : memberTypes.length; + int fieldIndex = 0; + int methodIndex = 0; + int memberTypeIndex = 0; + boolean isInterface = typeDeclaration.isInterface(); + + if (notifyTypePresence){ + char[][] interfaceNames = null; + int superInterfacesLength = 0; + TypeReference[] superInterfaces = typeDeclaration.superInterfaces; + if (superInterfaces != null) { + superInterfacesLength = superInterfaces.length; + interfaceNames = new char[superInterfacesLength][]; + } else { + if (typeDeclaration instanceof AnonymousLocalTypeDeclaration) { + // see PR 3442 + QualifiedAllocationExpression alloc = ((AnonymousLocalTypeDeclaration)typeDeclaration).allocation; + if (alloc != null && alloc.type != null) { + superInterfaces = new TypeReference[] { ((AnonymousLocalTypeDeclaration)typeDeclaration).allocation.type}; + superInterfacesLength = 1; + interfaceNames = new char[1][]; + } + } + } + if (superInterfaces != null) { + for (int i = 0; i < superInterfacesLength; i++) { + interfaceNames[i] = + CharOperation.concatWith(superInterfaces[i].getTypeName(), '.'); + } + } + if (isInterface) { + if (isInRange){ + requestor.enterInterface( + typeDeclaration.declarationSourceStart, + typeDeclaration.modifiers & AccJustFlag, + typeDeclaration.name, + typeDeclaration.sourceStart, + typeDeclaration.sourceEnd, + interfaceNames); + } + if (nestedTypeIndex == typeNames.length) { + // need a resize + System.arraycopy(typeNames, 0, (typeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex); + System.arraycopy(superTypeNames, 0, (superTypeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex); + } + typeNames[nestedTypeIndex] = typeDeclaration.name; + superTypeNames[nestedTypeIndex++] = JAVA_LANG_OBJECT; + } else { + TypeReference superclass = typeDeclaration.superclass; + if (superclass == null) { + if (isInRange){ + requestor.enterClass( + typeDeclaration.declarationSourceStart, + typeDeclaration.modifiers, + typeDeclaration.name, + typeDeclaration.sourceStart, + typeDeclaration.sourceEnd, + null, + interfaceNames); + } + } else { + if (isInRange){ + requestor.enterClass( + typeDeclaration.declarationSourceStart, + typeDeclaration.modifiers, + typeDeclaration.name, + typeDeclaration.sourceStart, + typeDeclaration.sourceEnd, + CharOperation.concatWith(superclass.getTypeName(), '.'), + interfaceNames); + } + } + if (nestedTypeIndex == typeNames.length) { + // need a resize + System.arraycopy(typeNames, 0, (typeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex); + System.arraycopy(superTypeNames, 0, (superTypeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex); + } + typeNames[nestedTypeIndex] = typeDeclaration.name; + superTypeNames[nestedTypeIndex++] = superclass == null ? JAVA_LANG_OBJECT : CharOperation.concatWith(superclass.getTypeName(), '.'); + } + } + while ((fieldIndex < fieldCount) + || (memberTypeIndex < memberTypeCount) + || (methodIndex < methodCount)) { + FieldDeclaration nextFieldDeclaration = null; + AbstractMethodDeclaration nextMethodDeclaration = null; + TypeDeclaration nextMemberDeclaration = null; + + int position = Integer.MAX_VALUE; + int nextDeclarationType = -1; + if (fieldIndex < fieldCount) { + nextFieldDeclaration = fields[fieldIndex]; + if (nextFieldDeclaration.declarationSourceStart < position) { + position = nextFieldDeclaration.declarationSourceStart; + nextDeclarationType = 0; // FIELD + } + } + if (methodIndex < methodCount) { + nextMethodDeclaration = methods[methodIndex]; + if (nextMethodDeclaration.declarationSourceStart < position) { + position = nextMethodDeclaration.declarationSourceStart; + nextDeclarationType = 1; // METHOD + } + } + if (memberTypeIndex < memberTypeCount) { + nextMemberDeclaration = memberTypes[memberTypeIndex]; + if (nextMemberDeclaration.declarationSourceStart < position) { + position = nextMemberDeclaration.declarationSourceStart; + nextDeclarationType = 2; // MEMBER + } + } + switch (nextDeclarationType) { + case 0 : + fieldIndex++; + notifySourceElementRequestor(nextFieldDeclaration); + break; + case 1 : + methodIndex++; + notifySourceElementRequestor(nextMethodDeclaration); + break; + case 2 : + memberTypeIndex++; + notifySourceElementRequestor(nextMemberDeclaration, true); + } + } + if (notifyTypePresence){ + if (isInRange){ + if (isInterface) { + requestor.exitInterface(typeDeclaration.declarationSourceEnd); + } else { + requestor.exitClass(typeDeclaration.declarationSourceEnd); + } + } + nestedTypeIndex--; + } +} +public void parseCompilationUnit( + ICompilationUnit unit, + int start, + int end, + boolean needReferenceInfo) { + + reportReferenceInfo = needReferenceInfo; + boolean old = diet; + if (needReferenceInfo) { + unknownRefs = new NameReference[10]; + unknownRefsCounter = 0; + } + try { + diet = true; + CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.options.maxProblemsPerUnit); + CompilationUnitDeclaration parsedUnit = parse(unit, compilationUnitResult, start, end); + if (needReferenceInfo){ + diet = false; + this.getMethodBodies(parsedUnit); + } + this.scanner.resetTo(start, end); + notifySourceElementRequestor(parsedUnit); + } catch (AbortCompilation e) { + } finally { + if (scanner.recordLineSeparator) { + requestor.acceptLineSeparatorPositions(scanner.getLineEnds()); + } + diet = old; + } +} +public void parseCompilationUnit( + ICompilationUnit unit, + boolean needReferenceInfo) { + boolean old = diet; + if (needReferenceInfo) { + unknownRefs = new NameReference[10]; + unknownRefsCounter = 0; + } + + try { +/* diet = !needReferenceInfo; + reportReferenceInfo = needReferenceInfo; + CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0); + parse(unit, compilationUnitResult); +*/ diet = true; + reportReferenceInfo = needReferenceInfo; + CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.options.maxProblemsPerUnit); + CompilationUnitDeclaration parsedUnit = parse(unit, compilationUnitResult); + int initialStart = this.scanner.initialPosition; + int initialEnd = this.scanner.eofPosition; + if (needReferenceInfo){ + diet = false; + this.getMethodBodies(parsedUnit); + } + this.scanner.resetTo(initialStart, initialEnd); + notifySourceElementRequestor(parsedUnit); + } catch (AbortCompilation e) { + } finally { + if (scanner.recordLineSeparator) { + requestor.acceptLineSeparatorPositions(scanner.getLineEnds()); + } + diet = old; + } +} +public void parseTypeMemberDeclarations( + ISourceType sourceType, + ICompilationUnit sourceUnit, + int start, + int end, + boolean needReferenceInfo) { + boolean old = diet; + if (needReferenceInfo) { + unknownRefs = new NameReference[10]; + unknownRefsCounter = 0; + } + + try { + diet = !needReferenceInfo; + reportReferenceInfo = needReferenceInfo; + CompilationResult compilationUnitResult = + new CompilationResult(sourceUnit, 0, 0, this.options.maxProblemsPerUnit); + CompilationUnitDeclaration unit = + SourceTypeConverter.buildCompilationUnit( + new ISourceType[]{sourceType}, + false, + false, + problemReporter(), + compilationUnitResult); + if ((unit == null) || (unit.types == null) || (unit.types.length != 1)) + return; + this.sourceType = sourceType; + try { + /* automaton initialization */ + initialize(); + goForClassBodyDeclarations(); + /* scanner initialization */ + scanner.setSource(sourceUnit.getContents()); + scanner.resetTo(start, end); + /* unit creation */ + referenceContext = compilationUnit = unit; + /* initialize the astStacl */ + // the compilationUnitDeclaration should contain exactly one type + pushOnAstStack(unit.types[0]); + /* run automaton */ + parse(); + notifySourceElementRequestor(unit); + } finally { + unit = compilationUnit; + compilationUnit = null; // reset parser + } + } catch (AbortCompilation e) { + } finally { + if (scanner.recordLineSeparator) { + requestor.acceptLineSeparatorPositions(scanner.getLineEnds()); + } + diet = old; + } +} + +public void parseTypeMemberDeclarations( + char[] contents, + int start, + int end) { + + boolean old = diet; + + try { + diet = true; + + /* automaton initialization */ + initialize(); + goForClassBodyDeclarations(); + /* scanner initialization */ + scanner.setSource(contents); + scanner.recordLineSeparator = false; + scanner.resetTo(start, end); + + /* unit creation */ + referenceContext = null; + + /* initialize the astStacl */ + // the compilationUnitDeclaration should contain exactly one type + /* run automaton */ + parse(); + notifySourceElementRequestor((CompilationUnitDeclaration)null); + } catch (AbortCompilation e) { + } finally { + diet = old; + } +} +/** + * Sort the given ast nodes by their positions. + */ +private static void quickSort(AstNode[] sortedCollection, int left, int right) { + int original_left = left; + int original_right = right; + AstNode mid = sortedCollection[ (left + right) / 2]; + do { + while (sortedCollection[left].sourceStart < mid.sourceStart) { + left++; + } + while (mid.sourceStart < sortedCollection[right].sourceStart) { + right--; + } + if (left <= right) { + AstNode tmp = sortedCollection[left]; + sortedCollection[left] = sortedCollection[right]; + sortedCollection[right] = tmp; + left++; + right--; + } + } while (left <= right); + if (original_left < right) { + quickSort(sortedCollection, original_left, right); + } + if (left < original_right) { + quickSort(sortedCollection, left, original_right); + } +} +/* + * Answer a char array representation of the type name formatted like: + * - type name + dimensions + * Example: + * "A[][]".toCharArray() + * "java.lang.String".toCharArray() + */ +private char[] returnTypeName(TypeReference type) { + if (type == null) + return null; + int dimension = type.dimensions(); + if (dimension != 0) { + char[] dimensionsArray = new char[dimension * 2]; + for (int i = 0; i < dimension; i++) { + dimensionsArray[i * 2] = '['; + dimensionsArray[(i * 2) + 1] = ']'; + } + return CharOperation.concat( + CharOperation.concatWith(type.getTypeName(), '.'), + dimensionsArray); + } + return CharOperation.concatWith(type.getTypeName(), '.'); +} + +public void addUnknownRef(NameReference nameRef) { + if (this.unknownRefs.length == this.unknownRefsCounter) { + // resize + System.arraycopy( + this.unknownRefs, + 0, + (this.unknownRefs = new NameReference[this.unknownRefsCounter * 2]), + 0, + this.unknownRefsCounter); + } + this.unknownRefs[this.unknownRefsCounter++] = nameRef; +} +private TypeReference typeReference( + int dim, + int localIdentifierPtr, + int localIdentifierLengthPtr) { + /* build a Reference on a variable that may be qualified or not + * This variable is a type reference and dim will be its dimensions. + * We don't have any side effect on the stacks' pointers. + */ + + int length; + TypeReference ref; + if ((length = identifierLengthStack[localIdentifierLengthPtr]) == 1) { + // single variable reference + if (dim == 0) { + ref = + new SingleTypeReference( + identifierStack[localIdentifierPtr], + identifierPositionStack[localIdentifierPtr--]); + } else { + ref = + new ArrayTypeReference( + identifierStack[localIdentifierPtr], + dim, + identifierPositionStack[localIdentifierPtr--]); + ref.sourceEnd = endPosition; + } + } else { + if (length < 0) { //flag for precompiled type reference on base types + ref = TypeReference.baseTypeReference(-length, dim); + ref.sourceStart = intStack[localIntPtr--]; + if (dim == 0) { + ref.sourceEnd = intStack[localIntPtr--]; + } else { + localIntPtr--; + ref.sourceEnd = endPosition; + } + } else { //Qualified variable reference + char[][] tokens = new char[length][]; + localIdentifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy(identifierStack, localIdentifierPtr + 1, tokens, 0, length); + System.arraycopy( + identifierPositionStack, + localIdentifierPtr + 1, + positions, + 0, + length); + if (dim == 0) { + ref = new QualifiedTypeReference(tokens, positions); + } else { + ref = new ArrayQualifiedTypeReference(tokens, dim, positions); + ref.sourceEnd = endPosition; + } + } + }; + return ref; +} + +private void visitIfNeeded(AbstractMethodDeclaration method) { + if (this.localDeclarationVisitor != null + && (method.bits & AstNode.HasLocalTypeMASK) != 0) { + if (method.statements != null) { + int statementsLength = method.statements.length; + for (int i = 0; i < statementsLength; i++) + method.statements[i].traverse(this.localDeclarationVisitor, method.scope); + } + } +} + +private void visitIfNeeded(FieldDeclaration field) { + if (this.localDeclarationVisitor != null + && (field.bits & AstNode.HasLocalTypeMASK) != 0) { + if (field.initialization != null) { + field.initialization.traverse(this.localDeclarationVisitor, null); + } + } +} + +private void visitIfNeeded(Initializer initializer) { + if (this.localDeclarationVisitor != null + && (initializer.bits & AstNode.HasLocalTypeMASK) != 0) { + if (initializer.block != null) { + initializer.block.traverse(this.localDeclarationVisitor, null); + } + } +} + +protected void reportSyntaxError(int act, int currentKind, int stateStackTop) { + if (compilationUnit == null) return; + super.reportSyntaxError(act, currentKind,stateStackTop); +} + +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/SourceElementRequestorAdapter.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/SourceElementRequestorAdapter.java new file mode 100644 index 0000000..e7aac88 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/SourceElementRequestorAdapter.java @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler; + +import net.sourceforge.phpdt.core.compiler.IProblem; + +public class SourceElementRequestorAdapter implements ISourceElementRequestor { + + /* + * @see ISourceElementRequestor#acceptConstructorReference(char[], int, int) + */ + public void acceptConstructorReference( + char[] typeName, + int argCount, + int sourcePosition) { + } + + /* + * @see ISourceElementRequestor#acceptFieldReference(char[], int) + */ + public void acceptFieldReference(char[] fieldName, int sourcePosition) { + } + + /* + * @see ISourceElementRequestor#acceptImport(int, int, char[], boolean) + */ + public void acceptImport( + int declarationStart, + int declarationEnd, + char[] name, + boolean onDemand) { + } + + /* + * @see ISourceElementRequestor#acceptLineSeparatorPositions(int[]) + */ + public void acceptLineSeparatorPositions(int[] positions) { + } + + /* + * @see ISourceElementRequestor#acceptMethodReference(char[], int, int) + */ + public void acceptMethodReference( + char[] methodName, + int argCount, + int sourcePosition) { + } + + /* + * @see ISourceElementRequestor#acceptPackage(int, int, char[]) + */ + public void acceptPackage( + int declarationStart, + int declarationEnd, + char[] name) { + } + + /* + * @see ISourceElementRequestor#acceptProblem(IProblem) + */ + public void acceptProblem(IProblem problem) { + } + + /* + * @see ISourceElementRequestor#acceptTypeReference(char[][], int, int) + */ + public void acceptTypeReference( + char[][] typeName, + int sourceStart, + int sourceEnd) { + } + + /* + * @see ISourceElementRequestor#acceptTypeReference(char[], int) + */ + public void acceptTypeReference(char[] typeName, int sourcePosition) { + } + + /* + * @see ISourceElementRequestor#acceptUnknownReference(char[][], int, int) + */ + public void acceptUnknownReference( + char[][] name, + int sourceStart, + int sourceEnd) { + } + + /* + * @see ISourceElementRequestor#acceptUnknownReference(char[], int) + */ + public void acceptUnknownReference(char[] name, int sourcePosition) { + } + + /* + * @see ISourceElementRequestor#enterClass(int, int, char[], int, int, char[], char[][]) + */ + public void enterClass( + int declarationStart, + int modifiers, + char[] name, + int nameSourceStart, + int nameSourceEnd, + char[] superclass, + char[][] superinterfaces) { + } + + /* + * @see ISourceElementRequestor#enterCompilationUnit() + */ + public void enterCompilationUnit() { + } + + /* + * @see ISourceElementRequestor#enterConstructor(int, int, char[], int, int, char[][], char[][], char[][]) + */ + public void enterConstructor( + int declarationStart, + int modifiers, + char[] name, + int nameSourceStart, + int nameSourceEnd, + char[][] parameterTypes, + char[][] parameterNames, + char[][] exceptionTypes) { + } + + /* + * @see ISourceElementRequestor#enterField(int, int, char[], char[], int, int) + */ + public void enterField( + int declarationStart, + int modifiers, + char[] type, + char[] name, + int nameSourceStart, + int nameSourceEnd) { + } + + /* + * @see ISourceElementRequestor#enterInitializer(int, int) + */ + public void enterInitializer(int declarationStart, int modifiers) { + } + + /* + * @see ISourceElementRequestor#enterInterface(int, int, char[], int, int, char[][]) + */ + public void enterInterface( + int declarationStart, + int modifiers, + char[] name, + int nameSourceStart, + int nameSourceEnd, + char[][] superinterfaces) { + } + + /* + * @see ISourceElementRequestor#enterMethod(int, int, char[], char[], int, int, char[][], char[][], char[][]) + */ + public void enterMethod( + int declarationStart, + int modifiers, + char[] returnType, + char[] name, + int nameSourceStart, + int nameSourceEnd, + char[][] parameterTypes, + char[][] parameterNames, + char[][] exceptionTypes) { + } + + /* + * @see ISourceElementRequestor#exitClass(int) + */ + public void exitClass(int declarationEnd) { + } + + /* + * @see ISourceElementRequestor#exitCompilationUnit(int) + */ + public void exitCompilationUnit(int declarationEnd) { + } + + /* + * @see ISourceElementRequestor#exitConstructor(int) + */ + public void exitConstructor(int declarationEnd) { + } + + /* + * @see ISourceElementRequestor#exitField(int) + */ + public void exitField(int declarationEnd) { + } + + /* + * @see ISourceElementRequestor#exitInitializer(int) + */ + public void exitInitializer(int declarationEnd) { + } + + /* + * @see ISourceElementRequestor#exitInterface(int) + */ + public void exitInterface(int declarationEnd) { + } + + /* + * @see ISourceElementRequestor#exitMethod(int) + */ + public void exitMethod(int declarationEnd) { + } + +} + diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AND_AND_Expression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AND_AND_Expression.java new file mode 100644 index 0000000..02f59de --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AND_AND_Expression.java @@ -0,0 +1,297 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +//dedicated treatment for the && +public class AND_AND_Expression extends BinaryExpression { + + int rightInitStateIndex = -1; + int mergedInitStateIndex = -1; + + public AND_AND_Expression(Expression left, Expression right, int operator) { + super(left, right, operator); + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + Constant opConstant = left.conditionalConstant(); + if (opConstant != NotAConstant) { + if (opConstant.booleanValue() == true) { + // TRUE && anything + // need to be careful of scenario: + // (x && y) && !z, if passing the left info to the right, it would be swapped by the ! + FlowInfo mergedInfo = left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + mergedInfo = right.analyseCode(currentScope, flowContext, mergedInfo); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + } + FlowInfo leftInfo = left.analyseCode(currentScope, flowContext, flowInfo); + // need to be careful of scenario: + // (x && y) && !z, if passing the left info to the right, it would be swapped by the ! + FlowInfo rightInfo = leftInfo.initsWhenTrue().unconditionalInits().copy(); + if (opConstant != NotAConstant && opConstant.booleanValue() == false) rightInfo.markAsFakeReachable(true); + + rightInitStateIndex = + currentScope.methodScope().recordInitializationStates(rightInfo); + rightInfo = right.analyseCode(currentScope, flowContext, rightInfo); + FlowInfo mergedInfo = + FlowInfo.conditional( + rightInfo.initsWhenTrue().copy(), + leftInfo.initsWhenFalse().copy().unconditionalInits().mergedWith( + rightInfo.initsWhenFalse().copy().unconditionalInits())); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + + /** + * Code generation for a binary operation + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + Label falseLabel, endLabel; + if (constant != Constant.NotAConstant) { + // inlined value + if (valueRequired) + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + bits |= OnlyValueRequiredMASK; + generateOptimizedBoolean( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + valueRequired); + /* improving code gen for such a case: boolean b = i < 0 && false + * since the label has never been used, we have the inlined value on the stack. */ + if (falseLabel.hasForwardReferences()) { + if (valueRequired) { + codeStream.iconst_1(); + if ((bits & ValueForReturnMASK) != 0) { + codeStream.ireturn(); + falseLabel.place(); + codeStream.iconst_0(); + } else { + codeStream.goto_(endLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + falseLabel.place(); + codeStream.iconst_0(); + endLabel.place(); + } + } else { + falseLabel.place(); + } + } + if (valueRequired) { + codeStream.generateImplicitConversion(implicitConversion); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + /** + * Boolean operator code generation + * Optimized operations are: && + */ + public void generateOptimizedBoolean( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) { + super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); + return; + } + int pc = codeStream.position; + Constant condConst; + if ((condConst = left.conditionalConstant()) != NotAConstant) { + if (condConst.booleanValue() == true) { + // && x + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if (rightInitStateIndex != -1) { + codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex); + } + if ((bits & OnlyValueRequiredMASK) != 0) { + right.generateCode(currentScope, codeStream, valueRequired); + } else { + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + } else { + // && x + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if (valueRequired) { + if ((bits & OnlyValueRequiredMASK) != 0) { + codeStream.iconst_0(); + } else { + if (falseLabel != null) { + // implicit falling through the TRUE case + codeStream.goto_(falseLabel); + } + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + } + return; + } + if ((condConst = right.conditionalConstant()) != NotAConstant) { + if (condConst.booleanValue() == true) { + // x && + if ((bits & OnlyValueRequiredMASK) != 0) { + left.generateCode(currentScope, codeStream, valueRequired); + } else { + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + if (rightInitStateIndex != -1) { + codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex); + } + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + } else { + // x && + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if (rightInitStateIndex != -1) { + codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex); + } + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if (valueRequired) { + if ((bits & OnlyValueRequiredMASK) != 0) { + codeStream.iconst_0(); + } else { + if (falseLabel != null) { + // implicit falling through the TRUE case + codeStream.goto_(falseLabel); + } + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + } + return; + } + // default case + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + Label internalFalseLabel = new Label(codeStream); + left.generateOptimizedBoolean( + currentScope, + codeStream, + null, + internalFalseLabel, + true); + if (rightInitStateIndex != -1) { + codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex); + } + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + null, + valueRequired); + internalFalseLabel.place(); + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + left.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, true); + if (rightInitStateIndex != -1) { + codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex); + } + right.generateOptimizedBoolean( + currentScope, + codeStream, + null, + falseLabel, + valueRequired); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + } + } + + public boolean isCompactableOperation() { + return false; + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + if (visitor.visit(this, scope)) { + left.traverse(visitor, scope); + right.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AbstractMethodDeclaration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AbstractMethodDeclaration.java new file mode 100644 index 0000000..214dc4c --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AbstractMethodDeclaration.java @@ -0,0 +1,398 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.core.compiler.*; +import net.sourceforge.phpdt.internal.compiler.*; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; +import net.sourceforge.phpdt.internal.compiler.parser.*; + +public abstract class AbstractMethodDeclaration + extends AstNode + implements ProblemSeverities, ReferenceContext { + + public MethodScope scope; + //it is not relevent for constructor but it helps to have the name of the constructor here + //which is always the name of the class.....parsing do extra work to fill it up while it do not have to.... + public char[] selector; + public int declarationSourceStart; + public int declarationSourceEnd; + public int modifiers; + public int modifiersSourceStart; + public Argument[] arguments; + public TypeReference[] thrownExceptions; + public Statement[] statements; + public int explicitDeclarations; + public MethodBinding binding; + public boolean ignoreFurtherInvestigation = false; + public boolean needFreeReturn = false; + + public int bodyStart; + public int bodyEnd = -1; + public CompilationResult compilationResult; + + AbstractMethodDeclaration(CompilationResult compilationResult){ + this.compilationResult = compilationResult; + } + + /* + * We cause the compilation task to abort to a given extent. + */ + public void abort(int abortLevel) { + + if (scope == null) { + throw new AbortCompilation(); // cannot do better + } + + CompilationResult compilationResult = + scope.referenceCompilationUnit().compilationResult; + + switch (abortLevel) { + case AbortCompilation : + throw new AbortCompilation(compilationResult); + case AbortCompilationUnit : + throw new AbortCompilationUnit(compilationResult); + case AbortType : + throw new AbortType(compilationResult); + default : + throw new AbortMethod(compilationResult); + } + } + + public void analyseCode( + ClassScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // starting of the code analysis for methods + if (ignoreFurtherInvestigation) + return; + try { + if (binding == null) + return; + // may be in a non necessary for innerclass with static final constant fields + if (binding.isAbstract() || binding.isNative()) + return; + + ExceptionHandlingFlowContext methodContext = + new ExceptionHandlingFlowContext( + flowContext, + this, + binding.thrownExceptions, + scope, + FlowInfo.DeadEnd); + + // propagate to statements + if (statements != null) { + for (int i = 0, count = statements.length; i < count; i++) { + Statement stat; + if (!flowInfo.complainIfUnreachable((stat = statements[i]), scope)) { + flowInfo = stat.analyseCode(scope, methodContext, flowInfo); + } + } + } + // check for missing returning path + TypeBinding returnType = binding.returnType; + if ((returnType == VoidBinding) || isAbstract()) { + needFreeReturn = + !((flowInfo == FlowInfo.DeadEnd) || flowInfo.isFakeReachable()); + } else { + if (flowInfo != FlowInfo.DeadEnd) { + // special test for empty methods that should return something + if ((statements == null) && (returnType != VoidBinding)) { + scope.problemReporter().shouldReturn(returnType, this); + } else { + scope.problemReporter().shouldReturn( + returnType, + statements[statements.length - 1]); + } + } + } + } catch (AbortMethod e) { + this.ignoreFurtherInvestigation = true; + } + } + + /** + * Bind and add argument's binding into the scope of the method + */ + public void bindArguments() { + + if (arguments != null) { + // by default arguments in abstract/native methods are considered to be used (no complaint is expected) + boolean used = binding == null || binding.isAbstract() || binding.isNative(); + + int length = arguments.length; + for (int i = 0; i < length; i++) { + TypeBinding argType = binding == null ? null : binding.parameters[i]; + arguments[i].bind(scope, argType, used); + } + } + } + + /** + * Record the thrown exception type bindings in the corresponding type references. + */ + public void bindThrownExceptions() { + + if (this.thrownExceptions != null + && this.binding != null + && this.binding.thrownExceptions != null) { + int length = this.binding.thrownExceptions.length; + for (int i = 0; i < length; i++) { + this.thrownExceptions[i].binding = this.binding.thrownExceptions[i]; + } + } + } + + public CompilationResult compilationResult() { + + return this.compilationResult; + } + + /** + * Bytecode generation for a method + */ + public void generateCode(ClassScope classScope, ClassFile classFile) { + + int problemResetPC = 0; + classFile.codeStream.wideMode = false; // reset wideMode to false + if (ignoreFurtherInvestigation) { + // method is known to have errors, dump a problem method + if (this.binding == null) + return; // handle methods with invalid signature or duplicates + int problemsLength; + IProblem[] problems = + scope.referenceCompilationUnit().compilationResult.getProblems(); + IProblem[] problemsCopy = new IProblem[problemsLength = problems.length]; + System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); + classFile.addProblemMethod(this, binding, problemsCopy); + return; + } + // regular code generation + try { + problemResetPC = classFile.contentsOffset; + this.generateCode(classFile); + } catch (AbortMethod e) { + // a fatal error was detected during code generation, need to restart code gen if possible + if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) { + // a branch target required a goto_w, restart code gen in wide mode. + try { + this.traverse(new ResetStateForCodeGenerationVisitor(), classScope); + classFile.contentsOffset = problemResetPC; + classFile.methodCount--; + classFile.codeStream.wideMode = true; // request wide mode + this.generateCode(classFile); // restart method generation + } catch (AbortMethod e2) { + int problemsLength; + IProblem[] problems = + scope.referenceCompilationUnit().compilationResult.getProblems(); + IProblem[] problemsCopy = new IProblem[problemsLength = problems.length]; + System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); + classFile.addProblemMethod(this, binding, problemsCopy, problemResetPC); + } + } else { + // produce a problem method accounting for this fatal error + int problemsLength; + IProblem[] problems = + scope.referenceCompilationUnit().compilationResult.getProblems(); + IProblem[] problemsCopy = new IProblem[problemsLength = problems.length]; + System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); + classFile.addProblemMethod(this, binding, problemsCopy, problemResetPC); + } + } + } + + private void generateCode(ClassFile classFile) { + + classFile.generateMethodInfoHeader(binding); + int methodAttributeOffset = classFile.contentsOffset; + int attributeNumber = classFile.generateMethodInfoAttribute(binding); + if ((!binding.isNative()) && (!binding.isAbstract())) { + int codeAttributeOffset = classFile.contentsOffset; + classFile.generateCodeAttributeHeader(); + CodeStream codeStream = classFile.codeStream; + codeStream.reset(this, classFile); + // initialize local positions + scope.computeLocalVariablePositions(binding.isStatic() ? 0 : 1, codeStream); + + // arguments initialization for local variable debug attributes + if (arguments != null) { + for (int i = 0, max = arguments.length; i < max; i++) { + LocalVariableBinding argBinding; + codeStream.addVisibleLocalVariable(argBinding = arguments[i].binding); + argBinding.recordInitializationStartPC(0); + } + } + if (statements != null) { + for (int i = 0, max = statements.length; i < max; i++) + statements[i].generateCode(scope, codeStream); + } + if (needFreeReturn) { + codeStream.return_(); + } + // local variable attributes + codeStream.exitUserScope(scope); + codeStream.recordPositionsFrom(0, this.bodyEnd); + classFile.completeCodeAttribute(codeAttributeOffset); + attributeNumber++; + } + classFile.completeMethodInfo(methodAttributeOffset, attributeNumber); + + // if a problem got reported during code gen, then trigger problem method creation + if (ignoreFurtherInvestigation) { + throw new AbortMethod(scope.referenceCompilationUnit().compilationResult); + } + } + + public boolean hasErrors() { + return this.ignoreFurtherInvestigation; + } + + public boolean isAbstract() { + + if (binding != null) + return binding.isAbstract(); + return (modifiers & AccAbstract) != 0; + } + + public boolean isClinit() { + + return false; + } + + public boolean isConstructor() { + + return false; + } + + public boolean isDefaultConstructor() { + + return false; + } + + public boolean isInitializationMethod() { + + return false; + } + + public boolean isNative() { + + if (binding != null) + return binding.isNative(); + return (modifiers & AccNative) != 0; + } + + public boolean isStatic() { + + if (binding != null) + return binding.isStatic(); + return (modifiers & AccStatic) != 0; + } + + /** + * Fill up the method body with statement + */ + public abstract void parseStatements( + Parser parser, + CompilationUnitDeclaration unit); + + public void resolve(ClassScope upperScope) { + + if (binding == null) { + ignoreFurtherInvestigation = true; + } + + try { + bindArguments(); + bindThrownExceptions(); + resolveStatements(upperScope); + } catch (AbortMethod e) { // ========= abort on fatal error ============= + this.ignoreFurtherInvestigation = true; + } + } + + public void resolveStatements(ClassScope upperScope) { + + if (statements != null) { + int i = 0, length = statements.length; + while (i < length) + statements[i++].resolve(scope); + } + } + + public String returnTypeToString(int tab) { + + return ""; //$NON-NLS-1$ + } + + public void tagAsHavingErrors() { + + ignoreFurtherInvestigation = true; + } + + public String toString(int tab) { + + String s = tabString(tab); + if (modifiers != AccDefault) { + s += modifiersString(modifiers); + } + + s += returnTypeToString(0); + s += new String(selector) + "("; //$NON-NLS-1$ + if (arguments != null) { + for (int i = 0; i < arguments.length; i++) { + s += arguments[i].toString(0); + if (i != (arguments.length - 1)) + s = s + ", "; //$NON-NLS-1$ + }; + }; + s += ")"; //$NON-NLS-1$ + if (thrownExceptions != null) { + s += " throws "; //$NON-NLS-1$ + for (int i = 0; i < thrownExceptions.length; i++) { + s += thrownExceptions[i].toString(0); + if (i != (thrownExceptions.length - 1)) + s = s + ", "; //$NON-NLS-1$ + }; + }; + + s += toStringStatements(tab + 1); + return s; + } + + public String toStringStatements(int tab) { + + if (isAbstract() || (this.modifiers & AccSemicolonBody) != 0) + return ";"; //$NON-NLS-1$ + + String s = " {"; //$NON-NLS-1$ + if (statements != null) { + for (int i = 0; i < statements.length; i++) { + s = s + "\n" + statements[i].toString(tab); //$NON-NLS-1$ + if (!(statements[i] instanceof Block)) { + s += ";"; //$NON-NLS-1$ + } + } + } + s += "\n" + tabString(tab == 0 ? 0 : tab - 1) + "}"; //$NON-NLS-2$ //$NON-NLS-1$ + return s; + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + ClassScope classScope) { + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AbstractVariableDeclaration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AbstractVariableDeclaration.java new file mode 100644 index 0000000..32835cb --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AbstractVariableDeclaration.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +public abstract class AbstractVariableDeclaration extends Statement { + public int modifiers; + + public TypeReference type; + public Expression initialization; + + public char[] name; + public int declarationEnd; + public int declarationSourceStart; + public int declarationSourceEnd; + public int modifiersSourceStart; + public AbstractVariableDeclaration() { + } + public abstract String name(); + + public String toString(int tab) { + + String s = tabString(tab); + if (modifiers != AccDefault) { + s += modifiersString(modifiers); + } + s += type.toString(0) + " " + new String(name()); //$NON-NLS-1$ + if (initialization != null) + s += " = " + initialization.toStringExpression(tab); //$NON-NLS-1$ + return s; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AllocationExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AllocationExpression.java new file mode 100644 index 0000000..3c999d0 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AllocationExpression.java @@ -0,0 +1,256 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class AllocationExpression + extends Expression + implements InvocationSite { + + public TypeReference type; + public Expression[] arguments; + public MethodBinding binding; + + MethodBinding syntheticAccessor; + + public AllocationExpression() { + super(); + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // must verify that exceptions potentially thrown by this expression are caught in the method + + // process arguments + if (arguments != null) { + for (int i = 0, count = arguments.length; i < count; i++) { + flowInfo = + arguments[i] + .analyseCode(currentScope, flowContext, flowInfo) + .unconditionalInits(); + } + } + // record some dependency information for exception types + ReferenceBinding[] thrownExceptions; + if (((thrownExceptions = binding.thrownExceptions).length) != 0) { + // check exception handling + flowContext.checkExceptionHandlers( + thrownExceptions, + this, + flowInfo, + currentScope); + } + manageEnclosingInstanceAccessIfNecessary(currentScope); + manageSyntheticAccessIfNecessary(currentScope); + return flowInfo; + } + + public Expression enclosingInstance() { + return null; + } + + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + ReferenceBinding allocatedType = binding.declaringClass; + + codeStream.new_(allocatedType); + if (valueRequired) { + codeStream.dup(); + } + // better highlight for allocation: display the type individually + codeStream.recordPositionsFrom(pc, type.sourceStart); + + // handling innerclass instance allocation + if (allocatedType.isNestedType()) { + codeStream.generateSyntheticArgumentValues( + currentScope, + allocatedType, + enclosingInstance(), + this); + } + // generate the arguments for constructor + if (arguments != null) { + for (int i = 0, count = arguments.length; i < count; i++) { + arguments[i].generateCode(currentScope, codeStream, true); + } + } + // invoke constructor + if (syntheticAccessor == null) { + codeStream.invokespecial(binding); + } else { + // synthetic accessor got some extra arguments appended to its signature, which need values + for (int i = 0, + max = syntheticAccessor.parameters.length - binding.parameters.length; + i < max; + i++) { + codeStream.aconst_null(); + } + codeStream.invokespecial(syntheticAccessor); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public boolean isSuperAccess() { + + return false; + } + + public boolean isTypeAccess() { + + return true; + } + + /* Inner emulation consists in either recording a dependency + * link only, or performing one level of propagation. + * + * Dependency mechanism is used whenever dealing with source target + * types, since by the time we reach them, we might not yet know their + * exact need. + */ + public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) { + + ReferenceBinding allocatedType; + + // perform some emulation work in case there is some and we are inside a local type only + if ((allocatedType = binding.declaringClass).isNestedType() + && currentScope.enclosingSourceType().isLocalType()) { + + if (allocatedType.isLocalType()) { + ((LocalTypeBinding) allocatedType).addInnerEmulationDependent( + currentScope, + false, + false); + // request cascade of accesses + } else { + // locally propagate, since we already now the desired shape for sure + currentScope.propagateInnerEmulation(allocatedType, false, false); + // request cascade of accesses + } + } + } + + public void manageSyntheticAccessIfNecessary(BlockScope currentScope) { + + if (binding.isPrivate() + && (currentScope.enclosingSourceType() != binding.declaringClass)) { + + if (currentScope + .environment() + .options + .isPrivateConstructorAccessChangingVisibility) { + binding.tagForClearingPrivateModifier(); + // constructor will not be dumped as private, no emulation required thus + } else { + syntheticAccessor = + ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding); + currentScope.problemReporter().needToEmulateMethodAccess(binding, this); + } + } + } + + public TypeBinding resolveType(BlockScope scope) { + + // Propagate the type checking to the arguments, and check if the constructor is defined. + constant = NotAConstant; + TypeBinding typeBinding = type.resolveType(scope); + // will check for null after args are resolved + + // buffering the arguments' types + TypeBinding[] argumentTypes = NoParameters; + if (arguments != null) { + boolean argHasError = false; + int length = arguments.length; + argumentTypes = new TypeBinding[length]; + for (int i = 0; i < length; i++) + if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null) + argHasError = true; + if (argHasError) + return typeBinding; + } + if (typeBinding == null) + return null; + + if (!typeBinding.canBeInstantiated()) { + scope.problemReporter().cannotInstantiate(type, typeBinding); + return typeBinding; + } + ReferenceBinding allocatedType = (ReferenceBinding) typeBinding; + if (!(binding = scope.getConstructor(allocatedType, argumentTypes, this)) + .isValidBinding()) { + if (binding.declaringClass == null) + binding.declaringClass = allocatedType; + scope.problemReporter().invalidConstructor(this, binding); + return typeBinding; + } + if (isMethodUseDeprecated(binding, scope)) + scope.problemReporter().deprecatedMethod(binding, this); + + if (arguments != null) + for (int i = 0; i < arguments.length; i++) + arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]); + return allocatedType; + } + + public void setActualReceiverType(ReferenceBinding receiverType) { + // ignored + } + + public void setDepth(int i) { + // ignored + } + + public void setFieldIndex(int i) { + // ignored + } + + public String toStringExpression() { + + String s = "new " + type.toString(0); //$NON-NLS-1$ + if (arguments == null) + s = s + "()"; //$NON-NLS-1$ + else { + s = s + "("; //$NON-NLS-1$ + for (int i = 0; i < arguments.length; i++) { + s = s + arguments[i].toStringExpression(); + if (i == (arguments.length - 1)) + s = s + ")"; //$NON-NLS-1$ + else + s = s + ", "; //$NON-NLS-1$ + } + } + return s; + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + int argumentsLength; + type.traverse(visitor, scope); + if (arguments != null) { + argumentsLength = arguments.length; + for (int i = 0; i < argumentsLength; i++) + arguments[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AnonymousLocalTypeDeclaration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AnonymousLocalTypeDeclaration.java new file mode 100644 index 0000000..bd66b66 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AnonymousLocalTypeDeclaration.java @@ -0,0 +1,170 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.CompilationResult; +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; + +public class AnonymousLocalTypeDeclaration extends LocalTypeDeclaration { + + public static final char[] ANONYMOUS_EMPTY_NAME = new char[] {}; + public QualifiedAllocationExpression allocation; + + public AnonymousLocalTypeDeclaration(CompilationResult compilationResult) { + super(compilationResult); + modifiers = AccDefault; + name = ANONYMOUS_EMPTY_NAME; + } + + // use a default name in order to th name lookup + // to operate juat like a regular type (which has a name) + //without checking systematically if the naem is null .... + public MethodBinding createsInternalConstructorWithBinding(MethodBinding inheritedConstructorBinding) { + + //Add to method'set, the default constuctor that just recall the + //super constructor with the same arguments + String baseName = "$anonymous"; //$NON-NLS-1$ + TypeBinding[] argumentTypes = inheritedConstructorBinding.parameters; + int argumentsLength = argumentTypes.length; + //the constructor + ConstructorDeclaration cd = new ConstructorDeclaration(this.compilationResult); + cd.selector = new char[] { 'x' }; //no maining + cd.sourceStart = sourceStart; + cd.sourceEnd = sourceEnd; + cd.modifiers = modifiers & AccVisibilityMASK; + cd.isDefaultConstructor = true; + + if (argumentsLength > 0) { + Argument[] arguments = (cd.arguments = new Argument[argumentsLength]); + for (int i = argumentsLength; --i >= 0;) { + arguments[i] = new Argument((baseName + i).toCharArray(), 0L, null /*type ref*/, AccDefault); + } + } + + //the super call inside the constructor + cd.constructorCall = + new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); + cd.constructorCall.sourceStart = sourceStart; + cd.constructorCall.sourceEnd = sourceEnd; + + if (argumentsLength > 0) { + Expression[] args; + args = cd.constructorCall.arguments = new Expression[argumentsLength]; + for (int i = argumentsLength; --i >= 0;) { + args[i] = new SingleNameReference((baseName + i).toCharArray(), 0L); + } + } + + //adding the constructor in the methods list + if (methods == null) { + methods = new AbstractMethodDeclaration[] { cd }; + } else { + AbstractMethodDeclaration[] newMethods; + System.arraycopy( + methods, + 0, + newMethods = new AbstractMethodDeclaration[methods.length + 1], + 1, + methods.length); + newMethods[0] = cd; + methods = newMethods; + } + + //============BINDING UPDATE========================== + cd.binding = new MethodBinding( + cd.modifiers, //methodDeclaration + argumentsLength == 0 ? NoParameters : argumentTypes, //arguments bindings + inheritedConstructorBinding.thrownExceptions, //exceptions + binding); //declaringClass + + cd.scope = new MethodScope(scope, this, true); + cd.bindArguments(); + cd.constructorCall.resolve(cd.scope); + + if (binding.methods == null) { + binding.methods = new MethodBinding[] { cd.binding }; + } else { + MethodBinding[] newMethods; + System.arraycopy( + binding.methods, + 0, + newMethods = new MethodBinding[binding.methods.length + 1], + 1, + binding.methods.length); + newMethods[0] = cd.binding; + binding.methods = newMethods; + } + //=================================================== + + return cd.binding; + + } + public void resolve(BlockScope scope) { + + // scope and binding are provided in updateBindingSuperclass + resolve(); + updateMaxFieldCount(); + } + + public String toString(int tab) { + + return toStringBody(tab); + } + + /** + * Iteration for a local anonymous innertype + * + */ + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + BlockScope blockScope) { + + if (ignoreFurtherInvestigation) + return; + try { + if (visitor.visit(this, blockScope)) { + + int fieldsLength; + int methodsLength; + int memberTypesLength; + + // is bound to the actual type from the allocation expression + // therefore it has already been iterated at this point. + + if (memberTypes != null) { + memberTypesLength = memberTypes.length; + for (int i = 0; i < memberTypesLength; i++) + memberTypes[i].traverse(visitor, scope); + } + if (fields != null) { + fieldsLength = fields.length; + for (int i = 0; i < fieldsLength; i++) { + FieldDeclaration field; + if ((field = fields[i]).isStatic()) { + // local type cannot have static fields + } else { + field.traverse(visitor, initializerScope); + } + } + } + if (methods != null) { + methodsLength = methods.length; + for (int i = 0; i < methodsLength; i++) + methods[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, blockScope); + } catch (AbortType e) { + } + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Argument.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Argument.java new file mode 100644 index 0000000..b1658bd --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Argument.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class Argument extends LocalDeclaration { + + public Argument(char[] name, long posNom, TypeReference tr, int modifiers) { + + super(null, name, (int) (posNom >>> 32), (int) posNom); + this.modifiers = modifiers; + type = tr; + this.bits |= IsLocalDeclarationReachableMASK; + } + + public void bind(MethodScope scope, TypeBinding typeBinding, boolean used) { + + if (this.type != null) + this.type.binding = typeBinding; + // record the resolved type into the type reference + int modifierFlag = this.modifiers; + if ((this.binding = scope.duplicateName(this.name)) != null) { + //the name already exist....may carry on with the first binding .... + scope.problemReporter().redefineArgument(this); + } else { + scope.addLocalVariable( + this.binding = + new LocalVariableBinding(this, typeBinding, modifierFlag, true)); + //true stand for argument instead of just local + if (typeBinding != null && isTypeUseDeprecated(typeBinding, scope)) + scope.problemReporter().deprecatedType(typeBinding, this.type); + this.binding.declaration = this; + this.binding.used = used; + } + } + + public TypeBinding resolveForCatch(BlockScope scope) { + + // resolution on an argument of a catch clause + // provide the scope with a side effect : insertion of a LOCAL + // that represents the argument. The type must be from JavaThrowable + + TypeBinding tb = type.resolveTypeExpecting(scope, scope.getJavaLangThrowable()); + if (tb == null) + return null; + if ((binding = scope.duplicateName(name)) != null) { + // the name already exists....may carry on with the first binding .... + scope.problemReporter().redefineArgument(this); + return null; + } + binding = new LocalVariableBinding(this, tb, modifiers, false); // argument decl, but local var (i.e. isArgument = false) + scope.addLocalVariable(binding); + binding.constant = NotAConstant; + return tb; + } + + public String toString(int tab) { + + String s = ""; //$NON-NLS-1$ + if (modifiers != AccDefault) { + s += modifiersString(modifiers); + } + if (type == null) { + s += " "; //$NON-NLS-1$ + } else { + s += type.toString(tab) + " "; //$NON-NLS-1$ + } + s += new String(name); + return s; + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + if (type != null) + type.traverse(visitor, scope); + if (initialization != null) + initialization.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ArrayAllocationExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ArrayAllocationExpression.java new file mode 100644 index 0000000..e313d57 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ArrayAllocationExpression.java @@ -0,0 +1,185 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class ArrayAllocationExpression extends Expression { + + public TypeReference type; + + //dimensions.length gives the number of dimensions, but the + // last ones may be nulled as in new int[4][5][][] + public Expression[] dimensions; + public ArrayInitializer initializer; + + public ArrayBinding arrayTb; + + /** + * ArrayAllocationExpression constructor comment. + */ + public ArrayAllocationExpression() { + super(); + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + for (int i = 0, max = dimensions.length; i < max; i++) { + Expression dim; + if ((dim = dimensions[i]) != null) { + flowInfo = dim.analyseCode(currentScope, flowContext, flowInfo); + } + } + if (initializer != null) { + return initializer.analyseCode(currentScope, flowContext, flowInfo); + } else { + return flowInfo; + } + } + + /** + * Code generation for a array allocation expression + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + ArrayBinding arrayBinding; + + if (initializer != null) { + initializer.generateCode(currentScope, codeStream, valueRequired); + return; + } + + int nonNullDimensionsLength = 0; + for (int i = 0, max = dimensions.length; i < max; i++) + if (dimensions[i] != null) { + dimensions[i].generateCode(currentScope, codeStream, true); + nonNullDimensionsLength++; + } + + // Generate a sequence of bytecodes corresponding to an array allocation + if ((arrayTb.isArrayType()) + && ((arrayBinding = (ArrayBinding) arrayTb).dimensions == 1)) { + // Mono-dimensional array + codeStream.newArray(currentScope, arrayBinding); + } else { + // Multi-dimensional array + codeStream.multianewarray(arrayTb, nonNullDimensionsLength); + } + + if (valueRequired) { + codeStream.generateImplicitConversion(implicitConversion); + } else { + codeStream.pop(); + } + + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public TypeBinding resolveType(BlockScope scope) { + + // Build an array type reference using the current dimensions + // The parser does not check for the fact that dimension may be null + // only at the -end- like new int [4][][]. The parser allows new int[][4][] + // so this must be checked here......(this comes from a reduction to LL1 grammar) + + TypeBinding referenceTb = type.resolveType(scope); + // will check for null after dimensions are checked + constant = Constant.NotAConstant; + if (referenceTb == VoidBinding) { + scope.problemReporter().cannotAllocateVoidArray(this); + referenceTb = null; // will return below + } + + // check the validity of the dimension syntax (and test for all null dimensions) + int lengthDim = -1; + for (int i = dimensions.length; --i >= 0;) { + if (dimensions[i] != null) { + if (lengthDim == -1) + lengthDim = i; + } else if ( + lengthDim != -1) { + // should not have an empty dimension before an non-empty one + scope.problemReporter().incorrectLocationForEmptyDimension(this, i); + return null; + } + } + if (referenceTb == null) + return null; + + // lengthDim == -1 says if all dimensions are nulled + // when an initializer is given, no dimension must be specified + if (initializer == null) { + if (lengthDim == -1) { + scope.problemReporter().mustDefineDimensionsOrInitializer(this); + return null; + } + } else if (lengthDim != -1) { + scope.problemReporter().cannotDefineDimensionsAndInitializer(this); + return null; + } + + // dimensions resolution + for (int i = 0; i <= lengthDim; i++) { + TypeBinding dimTb = dimensions[i].resolveTypeExpecting(scope, IntBinding); + if (dimTb == null) + return null; + dimensions[i].implicitWidening(IntBinding, dimTb); + } + + // building the array binding + arrayTb = scope.createArray(referenceTb, dimensions.length); + + // check the initializer + if (initializer != null) + if ((initializer.resolveTypeExpecting(scope, arrayTb)) != null) + initializer.binding = arrayTb; + return arrayTb; + } + + public String toStringExpression() { + + String s = "new " + type.toString(0); //$NON-NLS-1$ + for (int i = 0; i < dimensions.length; i++) { + if (dimensions[i] == null) + s = s + "[]"; //$NON-NLS-1$ + else + s = s + "[" + dimensions[i].toStringExpression() + "]"; //$NON-NLS-2$ //$NON-NLS-1$ + } + if (initializer != null) + s = s + initializer.toStringExpression(); + return s; + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + int dimensionsLength = dimensions.length; + type.traverse(visitor, scope); + for (int i = 0; i < dimensionsLength; i++) { + if (dimensions[i] != null) + dimensions[i].traverse(visitor, scope); + } + if (initializer != null) + initializer.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ArrayInitializer.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ArrayInitializer.java new file mode 100644 index 0000000..d9fe989 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ArrayInitializer.java @@ -0,0 +1,188 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class ArrayInitializer extends Expression { + public Expression[] expressions; + public ArrayBinding binding; //the type of the { , , , } + +/** + * ArrayInitializer constructor comment. + */ +public ArrayInitializer() { + super(); +} +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + if (expressions != null) { + for (int i = 0, max = expressions.length; i < max; i++) { + flowInfo = expressions[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + } + } + return flowInfo; +} +/** + * Code generation for a array initializer + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + // Flatten the values and compute the dimensions, by iterating in depth into nested array initializers + + int pc = codeStream.position; + int expressionLength = (expressions == null) ? 0: expressions.length; + codeStream.generateInlinedValue(expressionLength); + codeStream.newArray(currentScope, binding); + if (expressions != null) { + // binding is an ArrayType, so I can just deal with the dimension + int elementsTypeID = binding.dimensions > 1 ? -1 : binding.leafComponentType.id; + for (int i = 0; i < expressionLength; i++) { + Expression expr; + if ((expr = expressions[i]).constant != NotAConstant) { + switch (elementsTypeID) { // filter out initializations to default values + case T_int : + case T_short : + case T_byte : + case T_char : + case T_float : + case T_long : + case T_double : + if (expr.constant.doubleValue() != 0) { + codeStream.dup(); + codeStream.generateInlinedValue(i); + expr.generateCode(currentScope, codeStream, true); + codeStream.arrayAtPut(elementsTypeID, false); + } + break; + case T_boolean : + if (expr.constant.booleanValue() != false) { + codeStream.dup(); + codeStream.generateInlinedValue(i); + expr.generateCode(currentScope, codeStream, true); + codeStream.arrayAtPut(elementsTypeID, false); + } + break; + default : + if (expr.constant != NullConstant.Default) { + codeStream.dup(); + codeStream.generateInlinedValue(i); + expr.generateCode(currentScope, codeStream, true); + codeStream.arrayAtPut(elementsTypeID, false); + } + } + } else { + codeStream.dup(); + codeStream.generateInlinedValue(i); + expr.generateCode(currentScope, codeStream, true); + codeStream.arrayAtPut(elementsTypeID, false); + } + } + } + if (!valueRequired) { + codeStream.pop(); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public TypeBinding resolveTypeExpecting(BlockScope scope, TypeBinding expectedTb) { + // Array initializers can only occur on the right hand side of an assignment + // expression, therefore the expected type contains the valid information + // concerning the type that must be enforced by the elements of the array initializer. + + // this method is recursive... (the test on isArrayType is the stop case) + + constant = NotAConstant; + if (expectedTb.isArrayType()) { + binding = (ArrayBinding) expectedTb; + if (expressions == null) + return binding; + TypeBinding expectedElementsTb = binding.elementsType(scope); + if (expectedElementsTb.isBaseType()) { + for (int i = 0, length = expressions.length; i < length; i++) { + Expression expression = expressions[i]; + TypeBinding expressionTb = + (expression instanceof ArrayInitializer) + ? expression.resolveTypeExpecting(scope, expectedElementsTb) + : expression.resolveType(scope); + if (expressionTb == null) + return null; + + // Compile-time conversion required? + if (expression.isConstantValueOfTypeAssignableToType(expressionTb, expectedElementsTb)) { + expression.implicitWidening(expectedElementsTb, expressionTb); + } else if (BaseTypeBinding.isWidening(expectedElementsTb.id, expressionTb.id)) { + expression.implicitWidening(expectedElementsTb, expressionTb); + } else { + scope.problemReporter().typeMismatchErrorActualTypeExpectedType(expression, expressionTb, expectedElementsTb); + return null; + } + } + } else { + for (int i = 0, length = expressions.length; i < length; i++) + if (expressions[i].resolveTypeExpecting(scope, expectedElementsTb) == null) + return null; + } + return binding; + } + + // infer initializer type for error reporting based on first element + TypeBinding leafElementType = null; + int dim = 1; + if (expressions == null) { + leafElementType = scope.getJavaLangObject(); + } else { + Expression currentExpression = expressions[0]; + while(currentExpression != null && currentExpression instanceof ArrayInitializer) { + dim++; + Expression[] subExprs = ((ArrayInitializer) currentExpression).expressions; + if (subExprs == null){ + leafElementType = scope.getJavaLangObject(); + currentExpression = null; + break; + } + currentExpression = ((ArrayInitializer) currentExpression).expressions[0]; + } + if (currentExpression != null) { + leafElementType = currentExpression.resolveType(scope); + } + } + if (leafElementType != null) { + TypeBinding probableTb = scope.createArray(leafElementType, dim); + scope.problemReporter().typeMismatchErrorActualTypeExpectedType(this, probableTb, expectedTb); + } + return null; +} +public String toStringExpression() { + + String s = "{" ; //$NON-NLS-1$ + if (expressions != null) + { int j = 20 ; + for (int i = 0 ; i < expressions.length ; i++) + { s = s + expressions[i].toStringExpression() + "," ; //$NON-NLS-1$ + j -- ; + if (j == 0) + { s = s + "\n "; j = 20;}}}; //$NON-NLS-1$ + s = s + "}"; //$NON-NLS-1$ + return s;} + +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + if (visitor.visit(this, scope)) { + if (expressions != null) { + int expressionsLength = expressions.length; + for (int i = 0; i < expressionsLength; i++) + expressions[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, scope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ArrayQualifiedTypeReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ArrayQualifiedTypeReference.java new file mode 100644 index 0000000..48f5515 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ArrayQualifiedTypeReference.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class ArrayQualifiedTypeReference extends QualifiedTypeReference { + int dimensions; +public ArrayQualifiedTypeReference(char[][] sources , int dim, long[] poss) { + super( sources , poss); + dimensions = dim ; +} +public ArrayQualifiedTypeReference(char[][] sources , TypeBinding tb, int dim, long[] poss) { + super( sources , tb, poss); + dimensions = dim ; +} +public int dimensions() { + return dimensions; +} +public TypeBinding getTypeBinding(Scope scope) { + if (binding != null) + return binding; + return scope.createArray(scope.getType(tokens), dimensions); +} +public String toStringExpression(int tab){ + /* slow speed */ + + String s = super.toStringExpression(tab) ; + if (dimensions == 1 ) return s + "[]" ; //$NON-NLS-1$ + for (int i=1 ; i <= dimensions ; i++) + s = s + "[]" ; //$NON-NLS-1$ + return s ; +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, ClassScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ArrayReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ArrayReference.java new file mode 100644 index 0000000..9ccea6b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ArrayReference.java @@ -0,0 +1,194 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class ArrayReference extends Reference { + + public Expression receiver; + public Expression position; + + public TypeBinding arrayElementBinding; + + public ArrayReference(Expression rec, Expression pos) { + this.receiver = rec; + this.position = pos; + sourceStart = rec.sourceStart; + } + + public FlowInfo analyseAssignment( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo, + Assignment assignment, + boolean compoundAssignment) { + + if (assignment.expression == null) { + return analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + } else { + return assignment + .expression + .analyseCode( + currentScope, + flowContext, + analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()) + .unconditionalInits(); + } + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + return position.analyseCode( + currentScope, + flowContext, + receiver.analyseCode(currentScope, flowContext, flowInfo)); + } + + public void generateAssignment( + BlockScope currentScope, + CodeStream codeStream, + Assignment assignment, + boolean valueRequired) { + + receiver.generateCode(currentScope, codeStream, true); + position.generateCode(currentScope, codeStream, true); + assignment.expression.generateCode(currentScope, codeStream, true); + codeStream.arrayAtPut(arrayElementBinding.id, valueRequired); + if (valueRequired) { + codeStream.generateImplicitConversion(assignment.implicitConversion); + } + } + + /** + * Code generation for a array reference + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + receiver.generateCode(currentScope, codeStream, true); + position.generateCode(currentScope, codeStream, true); + codeStream.arrayAt(arrayElementBinding.id); + // Generating code for the potential runtime type checking + if (valueRequired) { + codeStream.generateImplicitConversion(implicitConversion); + } else { + if (arrayElementBinding == LongBinding + || arrayElementBinding == DoubleBinding) { + codeStream.pop2(); + } else { + codeStream.pop(); + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public void generateCompoundAssignment( + BlockScope currentScope, + CodeStream codeStream, + Expression expression, + int operator, + int assignmentImplicitConversion, + boolean valueRequired) { + + receiver.generateCode(currentScope, codeStream, true); + position.generateCode(currentScope, codeStream, true); + codeStream.dup2(); + codeStream.arrayAt(arrayElementBinding.id); + int operationTypeID; + if ((operationTypeID = implicitConversion >> 4) == T_String) { + codeStream.generateStringAppend(currentScope, null, expression); + } else { + // promote the array reference to the suitable operation type + codeStream.generateImplicitConversion(implicitConversion); + // generate the increment value (will by itself be promoted to the operation value) + if (expression == IntLiteral.One) { // prefix operation + codeStream.generateConstant(expression.constant, implicitConversion); + } else { + expression.generateCode(currentScope, codeStream, true); + } + // perform the operation + codeStream.sendOperator(operator, operationTypeID); + // cast the value back to the array reference type + codeStream.generateImplicitConversion(assignmentImplicitConversion); + } + codeStream.arrayAtPut(arrayElementBinding.id, valueRequired); + } + + public void generatePostIncrement( + BlockScope currentScope, + CodeStream codeStream, + CompoundAssignment postIncrement, + boolean valueRequired) { + + receiver.generateCode(currentScope, codeStream, true); + position.generateCode(currentScope, codeStream, true); + codeStream.dup2(); + codeStream.arrayAt(arrayElementBinding.id); + if (valueRequired) { + if ((arrayElementBinding == LongBinding) + || (arrayElementBinding == DoubleBinding)) { + codeStream.dup2_x2(); + } else { + codeStream.dup_x2(); + } + } + codeStream.generateConstant( + postIncrement.expression.constant, + implicitConversion); + codeStream.sendOperator(postIncrement.operator, arrayElementBinding.id); + codeStream.generateImplicitConversion( + postIncrement.assignmentImplicitConversion); + codeStream.arrayAtPut(arrayElementBinding.id, false); + } + + public TypeBinding resolveType(BlockScope scope) { + + constant = Constant.NotAConstant; + TypeBinding arrayTb = receiver.resolveType(scope); + if (arrayTb == null) + return null; + if (!arrayTb.isArrayType()) { + scope.problemReporter().referenceMustBeArrayTypeAt(arrayTb, this); + return null; + } + TypeBinding positionTb = position.resolveTypeExpecting(scope, IntBinding); + if (positionTb == null) + return null; + position.implicitWidening(IntBinding, positionTb); + return arrayElementBinding = ((ArrayBinding) arrayTb).elementsType(scope); + } + + public String toStringExpression() { + + return receiver.toStringExpression() + "[" //$NON-NLS-1$ + +position.toStringExpression() + "]"; //$NON-NLS-1$ + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + receiver.traverse(visitor, scope); + position.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ArrayTypeReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ArrayTypeReference.java new file mode 100644 index 0000000..6c812cc --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ArrayTypeReference.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class ArrayTypeReference extends SingleTypeReference { + public int dimensions; +/** + * ArrayTypeReference constructor comment. + * @param source char[] + * @param dim int + * @param pos int + */ +public ArrayTypeReference(char[] source, int dim, long pos) { + super(source, pos); + dimensions = dim ; +} +public ArrayTypeReference(char[] source, TypeBinding tb, int dim, long pos) { + super(source, tb, pos); + dimensions = dim ;} +public int dimensions() { + return dimensions; +} +public TypeBinding getTypeBinding(Scope scope) { + if (binding != null) + return binding; + return scope.createArray(scope.getType(token), dimensions); +} +public String toStringExpression(int tab){ + /* slow speed */ + + String s = super.toStringExpression(tab) ; + if (dimensions == 1 ) return s + "[]" ; //$NON-NLS-1$ + for (int i=1 ; i <= dimensions ; i++) + s = s + "[]" ; //$NON-NLS-1$ + return s ; +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AssertStatement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AssertStatement.java new file mode 100644 index 0000000..66a16eb --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AssertStatement.java @@ -0,0 +1,172 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; + +public class AssertStatement extends Statement { + + public Expression assertExpression, exceptionArgument; + + // for local variable attribute + int preAssertInitStateIndex = -1; + private FieldBinding assertionSyntheticFieldBinding; + + public AssertStatement( + Expression exceptionArgument, + Expression assertExpression, + int startPosition) { + + this.assertExpression = assertExpression; + this.exceptionArgument = exceptionArgument; + sourceStart = startPosition; + sourceEnd = exceptionArgument.sourceEnd; + } + + public AssertStatement(Expression assertExpression, int startPosition) { + + this.assertExpression = assertExpression; + sourceStart = startPosition; + sourceEnd = assertExpression.sourceEnd; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + Constant constant = assertExpression.constant; + if (constant != NotAConstant && constant.booleanValue() == true) { + return flowInfo; + } + + preAssertInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo); + FlowInfo assertInfo = flowInfo.copy(); + + if (exceptionArgument != null) { + assertInfo = exceptionArgument.analyseCode( + currentScope, + flowContext, + assertExpression.analyseCode(currentScope, flowContext, assertInfo).unconditionalInits()) + .unconditionalInits(); + } else { + assertInfo = assertExpression.analyseCode(currentScope, flowContext, assertInfo).unconditionalInits(); + } + + // assertion might throw AssertionError (unchecked), which can have consequences in term of + // definitely assigned variables (depending on caught exception in the context) + // DISABLED - AssertionError is unchecked, try statements are already protected against these. + //flowContext.checkExceptionHandlers(currentScope.getJavaLangAssertionError(), this, assertInfo, currentScope); + + // only retain potential initializations + flowInfo.addPotentialInitializationsFrom(assertInfo.unconditionalInits()); + + // add the assert support in the clinit + manageSyntheticAccessIfNecessary(currentScope); + + return flowInfo; + } + + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + + if (this.assertionSyntheticFieldBinding != null) { + Label assertionActivationLabel = new Label(codeStream); + codeStream.getstatic(this.assertionSyntheticFieldBinding); + codeStream.ifne(assertionActivationLabel); + Label falseLabel = new Label(codeStream); + assertExpression.generateOptimizedBoolean(currentScope, codeStream, (falseLabel = new Label(codeStream)), null , true); + codeStream.newJavaLangAssertionError(); + codeStream.dup(); + if (exceptionArgument != null) { + exceptionArgument.generateCode(currentScope, codeStream, true); + codeStream.invokeJavaLangAssertionErrorConstructor(exceptionArgument.implicitConversion & 0xF); + } else { + codeStream.invokeJavaLangAssertionErrorDefaultConstructor(); + } + codeStream.athrow(); + falseLabel.place(); + assertionActivationLabel.place(); + } + + // May loose some local variable initializations : affecting the local variable attributes + if (preAssertInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, preAssertInitStateIndex); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public void resolve(BlockScope scope) { + + assertExpression.resolveTypeExpecting(scope, BooleanBinding); + if (exceptionArgument != null) { + TypeBinding exceptionArgumentType = exceptionArgument.resolveType(scope); + if (exceptionArgumentType != null){ + if (exceptionArgumentType.id == T_void){ + scope.problemReporter().illegalVoidExpression(exceptionArgument); + } + exceptionArgument.implicitConversion = (exceptionArgumentType.id << 4) + exceptionArgumentType.id; + } + } + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + assertExpression.traverse(visitor, scope); + if (exceptionArgument != null) { + exceptionArgument.traverse(visitor, scope); + } + } + visitor.endVisit(this, scope); + } + + public void manageSyntheticAccessIfNecessary(BlockScope currentScope) { + + // need assertion flag: $assertionsDisabled on outer most source type + ClassScope outerMostClassScope = currentScope.outerMostClassScope(); + SourceTypeBinding sourceTypeBinding = outerMostClassScope.enclosingSourceType(); + this.assertionSyntheticFieldBinding = sourceTypeBinding.addSyntheticField(this, currentScope); + + // find and enable assertion support + TypeDeclaration typeDeclaration = outerMostClassScope.referenceType(); + AbstractMethodDeclaration[] methods = typeDeclaration.methods; + for (int i = 0, max = methods.length; i < max; i++) { + AbstractMethodDeclaration method = methods[i]; + if (method.isClinit()) { + ((Clinit) method).addSupportForAssertion(assertionSyntheticFieldBinding); + break; + } + } + } + + public String toString(int tab) { + + StringBuffer buffer = new StringBuffer(tabString(tab)); + buffer.append("assert"); //$NON-NLS-1$ + buffer.append(this.assertExpression); + if (this.exceptionArgument != null) { + buffer.append(":"); //$NON-NLS-1$ + buffer.append(this.exceptionArgument); + buffer.append(";"); //$NON-NLS-1$ + } + return buffer.toString(); + } + +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Assignment.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Assignment.java new file mode 100644 index 0000000..5f7c560 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Assignment.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class Assignment extends Expression { + + public Reference lhs; + public Expression expression; + public TypeBinding lhsType; + + public Assignment(Expression lhs, Expression expression, int sourceEnd) { + //lhs is always a reference by construction , + //but is build as an expression ==> the checkcast cannot fail + + this.lhs = (Reference) lhs; + this.expression = expression; + + this.sourceStart = lhs.sourceStart; + this.sourceEnd = sourceEnd; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + // record setting a variable: various scenarii are possible, setting an array reference, + // a field reference, a blank final field reference, a field of an enclosing instance or + // just a local variable. + + return lhs + .analyseAssignment(currentScope, flowContext, flowInfo, this, false) + .unconditionalInits(); + } + + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + // various scenarii are possible, setting an array reference, + // a field reference, a blank final field reference, a field of an enclosing instance or + // just a local variable. + + int pc = codeStream.position; + lhs.generateAssignment(currentScope, codeStream, this, valueRequired); + // variable may have been optimized out + // the lhs is responsible to perform the implicitConversion generation for the assignment since optimized for unused local assignment. + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public TypeBinding resolveType(BlockScope scope) { + + // due to syntax lhs may be only a NameReference, a FieldReference or an ArrayReference + constant = NotAConstant; + this.lhsType = lhs.resolveType(scope); + TypeBinding expressionTb = expression.resolveType(scope); + if (this.lhsType == null || expressionTb == null) + return null; + + // Compile-time conversion of base-types : implicit narrowing integer into byte/short/character + // may require to widen the rhs expression at runtime + if ((expression.isConstantValueOfTypeAssignableToType(expressionTb, this.lhsType) + || (this.lhsType.isBaseType() && BaseTypeBinding.isWidening(this.lhsType.id, expressionTb.id))) + || (scope.areTypesCompatible(expressionTb, this.lhsType))) { + expression.implicitWidening(this.lhsType, expressionTb); + return this.lhsType; + } + scope.problemReporter().typeMismatchErrorActualTypeExpectedType( + expression, + expressionTb, + this.lhsType); + return null; + } + + public String toString(int tab) { + + //no () when used as a statement + return tabString(tab) + toStringExpressionNoParenthesis(); + } + + public String toStringExpression() { + + //subclass redefine toStringExpressionNoParenthesis() + return "(" + toStringExpressionNoParenthesis() + ")"; //$NON-NLS-2$ //$NON-NLS-1$ + } + + public String toStringExpressionNoParenthesis() { + + return lhs.toStringExpression() + " " //$NON-NLS-1$ + + "=" //$NON-NLS-1$ + + ((expression.constant != null) && (expression.constant != NotAConstant) + ? " /*cst:" + expression.constant.toString() + "*/ " //$NON-NLS-1$ //$NON-NLS-2$ + : " ") //$NON-NLS-1$ + + expression.toStringExpression(); + } + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + lhs.traverse(visitor, scope); + expression.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AstNode.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AstNode.java new file mode 100644 index 0000000..902277e --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AstNode.java @@ -0,0 +1,208 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; + +public abstract class AstNode implements BaseTypes, CompilerModifiers, TypeConstants, TypeIds { + + public int sourceStart, sourceEnd; + + //some global provision for the hierarchy + public final static Constant NotAConstant = Constant.NotAConstant; + + // storage for internal flags (32 bits) + public int bits = IsReachableMASK; // reachable by default + + // for operators only + // Reach . . . . . . . . . . . . . . . . . O O O O O O V VrR R R R + public static final int ReturnTypeIDMASK = 15; // 4 lower bits for operators + public static final int ValueForReturnMASK = 16; // for binary expressions + public static final int OnlyValueRequiredMASK = 32; // for binary expressions + public static final int OperatorSHIFT = 6; + public static final int OperatorMASK = 63 << OperatorSHIFT; + + // for name references only + // Reach . . . . . . . . . . . . . . . . D D D D D D D D VrF R R R + public static final int RestrictiveFlagMASK = 7; + // 3 lower bits for name references + public static final int FirstAssignmentToLocalMASK = 8; + // for single name references + public static final int DepthSHIFT = 5; + public static final int DepthMASK = 0xFF << DepthSHIFT; + // 8 bits for actual depth value (max. 255) + + // for statements only + public static final int IsReachableMASK = 0x80000000; // highest bit + public static final int IsLocalDeclarationReachableMASK = 0x40000000; // below highest bit + + // for type declaration only + public static final int AddAssertionMASK = 1; // lowest bit + + // for type, method and field declarations only + public static final int HasLocalTypeMASK = 2; + // cannot conflict with AddAssertionMASK + + /* + public final static int BitMask1= 0x1; // decimal 1 + public final static int BitMask2= 0x2; // decimal 2 + public final static int BitMask3= 0x4; // decimal 4 + public final static int BitMask4= 0x8; // decimal 8 + public final static int BitMask5= 0x10; // decimal 16 + public final static int BitMask6= 0x20; // decimal 32 + public final static int BitMask7= 0x40; // decimal 64 + public final static int BitMask8= 0x80; // decimal 128 + public final static int BitMask9= 0x100; // decimal 256 + public final static int BitMask10= 0x200; // decimal 512 + public final static int BitMask11= 0x400; // decimal 1024 + public final static int BitMask12= 0x800; // decimal 2048 + public final static int BitMask13= 0x1000; // decimal 4096 + public final static int BitMask14= 0x2000; // decimal 8192 + public final static int BitMask15= 0x4000; // decimal 16384 + public final static int BitMask16= 0x8000; // decimal 32768 + public final static int BitMask17= 0x10000; // decimal 65536 + public final static int BitMask18= 0x20000; // decimal 131072 + public final static int BitMask19= 0x40000; // decimal 262144 + public final static int BitMask20= 0x80000; // decimal 524288 + public final static int BitMask21= 0x100000; // decimal 1048576 + public final static int BitMask22= 0x200000; // decimal 2097152 + public final static int BitMask23= 0x400000; // decimal 4194304 + public final static int BitMask24= 0x800000; // decimal 8388608 + public final static int BitMask25= 0x1000000; // decimal 16777216 + public final static int BitMask26= 0x2000000; // decimal 33554432 + public final static int BitMask27= 0x4000000; // decimal 67108864 + public final static int BitMask28= 0x8000000; // decimal 134217728 + public final static int BitMask29= 0x10000000; // decimal 268435456 + public final static int BitMask30= 0x20000000; // decimal 536870912 + public final static int BitMask31= 0x40000000; // decimal 1073741824 + public final static int BitMask32= 0x80000000; // decimal 2147483648 + */ + + /** + * AstNode constructor comment. + */ + public AstNode() { + + super(); + } + + public boolean cannotReturn() { + return false; + } + + public AstNode concreteStatement() { + return this; + } + + /* Answer true if the field use is considered deprecated. + * An access in the same compilation unit is allowed. + */ + public final boolean isFieldUseDeprecated(FieldBinding field, Scope scope) { + + return field.isViewedAsDeprecated() + && !scope.isDefinedInSameUnit(field.declaringClass); + } + + /* Answer true if the method use is considered deprecated. + * An access in the same compilation unit is allowed. + */ + public final boolean isMethodUseDeprecated(MethodBinding method, Scope scope) { + return method.isViewedAsDeprecated() + && !scope.isDefinedInSameUnit(method.declaringClass); + } + + public boolean isSuper() { + + return false; + } + + public boolean isThis() { + + return false; + } + + /* Answer true if the type use is considered deprecated. + * An access in the same compilation unit is allowed. + */ + public final boolean isTypeUseDeprecated(TypeBinding type, Scope scope) { + + if (type.isArrayType()) + type = ((ArrayBinding) type).leafComponentType; + if (type.isBaseType()) + return false; + + ReferenceBinding refType = (ReferenceBinding) type; + return refType.isViewedAsDeprecated() && !scope.isDefinedInSameUnit(refType); + } + + public static String modifiersString(int modifiers) { + + String s = ""; //$NON-NLS-1$ + if ((modifiers & AccPublic) != 0) + s = s + "public "; //$NON-NLS-1$ + if ((modifiers & AccPrivate) != 0) + s = s + "private "; //$NON-NLS-1$ + if ((modifiers & AccProtected) != 0) + s = s + "protected "; //$NON-NLS-1$ + if ((modifiers & AccStatic) != 0) + s = s + "static "; //$NON-NLS-1$ + if ((modifiers & AccFinal) != 0) + s = s + "final "; //$NON-NLS-1$ + if ((modifiers & AccSynchronized) != 0) + s = s + "synchronized "; //$NON-NLS-1$ + if ((modifiers & AccVolatile) != 0) + s = s + "volatile "; //$NON-NLS-1$ + if ((modifiers & AccTransient) != 0) + s = s + "transient "; //$NON-NLS-1$ + if ((modifiers & AccNative) != 0) + s = s + "native "; //$NON-NLS-1$ + if ((modifiers & AccAbstract) != 0) + s = s + "abstract "; //$NON-NLS-1$ + return s; + } + + /** + * @deprecated - use field instead + */ + public int sourceEnd() { + return sourceEnd; + } + + /** + * @deprecated - use field instead + */ + public int sourceStart() { + return sourceStart; + } + + public static String tabString(int tab) { + + String s = ""; //$NON-NLS-1$ + for (int i = tab; i > 0; i--) + s = s + " "; //$NON-NLS-1$ + return s; + } + + public String toString() { + + return toString(0); + } + + public String toString(int tab) { + + return "****" + super.toString() + "****"; //$NON-NLS-2$ //$NON-NLS-1$ + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/BinaryExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/BinaryExpression.java new file mode 100644 index 0000000..f094885 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/BinaryExpression.java @@ -0,0 +1,1738 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class BinaryExpression extends OperatorExpression { + + public Expression left, right; + public Constant optimizedBooleanConstant; + + public BinaryExpression(Expression left, Expression right, int operator) { + + this.left = left; + this.right = right; + this.bits |= operator << OperatorSHIFT; // encode operator + this.sourceStart = left.sourceStart; + this.sourceEnd = right.sourceEnd; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + return right + .analyseCode( + currentScope, + flowContext, + left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()) + .unconditionalInits(); + } + + public void computeConstant(BlockScope scope, int leftId, int rightId) { + + //compute the constant when valid + if ((left.constant != Constant.NotAConstant) + && (right.constant != Constant.NotAConstant)) { + try { + constant = + Constant.computeConstantOperation( + left.constant, + leftId, + (bits & OperatorMASK) >> OperatorSHIFT, + right.constant, + rightId); + } catch (ArithmeticException e) { + constant = Constant.NotAConstant; + // 1.2 no longer throws an exception at compile-time + //scope.problemReporter().compileTimeConstantThrowsArithmeticException(this); + } + } else { + constant = Constant.NotAConstant; + //add some work for the boolean operators & | + optimizedBooleanConstant( + leftId, + (bits & OperatorMASK) >> OperatorSHIFT, + rightId); + } + } + + public Constant conditionalConstant() { + + return optimizedBooleanConstant == null ? constant : optimizedBooleanConstant; + } + + /** + * Code generation for a binary operation + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + Label falseLabel, endLabel; + if (constant != Constant.NotAConstant) { + if (valueRequired) + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + bits |= OnlyValueRequiredMASK; + switch ((bits & OperatorMASK) >> OperatorSHIFT) { + case PLUS : + switch (bits & ReturnTypeIDMASK) { + case T_String : + codeStream.generateStringAppend(currentScope, left, right); + if (!valueRequired) + codeStream.pop(); + break; + case T_int : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.iadd(); + break; + case T_long : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.ladd(); + break; + case T_double : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.dadd(); + break; + case T_float : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.fadd(); + break; + } + break; + case MINUS : + switch (bits & ReturnTypeIDMASK) { + case T_int : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.isub(); + break; + case T_long : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.lsub(); + break; + case T_double : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.dsub(); + break; + case T_float : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.fsub(); + break; + } + break; + case MULTIPLY : + switch (bits & ReturnTypeIDMASK) { + case T_int : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.imul(); + break; + case T_long : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.lmul(); + break; + case T_double : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.dmul(); + break; + case T_float : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.fmul(); + break; + } + break; + case DIVIDE : + switch (bits & ReturnTypeIDMASK) { + case T_int : + left.generateCode(currentScope, codeStream, true); + right.generateCode(currentScope, codeStream, true); + codeStream.idiv(); + if (!valueRequired) + codeStream.pop(); + break; + case T_long : + left.generateCode(currentScope, codeStream, true); + right.generateCode(currentScope, codeStream, true); + codeStream.ldiv(); + if (!valueRequired) + codeStream.pop2(); + break; + case T_double : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.ddiv(); + break; + case T_float : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.fdiv(); + break; + } + break; + case REMAINDER : + switch (bits & ReturnTypeIDMASK) { + case T_int : + left.generateCode(currentScope, codeStream, true); + right.generateCode(currentScope, codeStream, true); + codeStream.irem(); + if (!valueRequired) + codeStream.pop(); + break; + case T_long : + left.generateCode(currentScope, codeStream, true); + right.generateCode(currentScope, codeStream, true); + codeStream.lrem(); + if (!valueRequired) + codeStream.pop2(); + break; + case T_double : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.drem(); + break; + case T_float : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.frem(); + break; + } + break; + case AND : + switch (bits & ReturnTypeIDMASK) { + case T_int : + // 0 & x + if ((left.constant != Constant.NotAConstant) + && (left.constant.typeID() == T_int) + && (left.constant.intValue() == 0)) { + right.generateCode(currentScope, codeStream, false); + if (valueRequired) + codeStream.iconst_0(); + } else { + // x & 0 + if ((right.constant != Constant.NotAConstant) + && (right.constant.typeID() == T_int) + && (right.constant.intValue() == 0)) { + left.generateCode(currentScope, codeStream, false); + if (valueRequired) + codeStream.iconst_0(); + } else { + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.iand(); + } + } + break; + case T_long : + // 0 & x + if ((left.constant != Constant.NotAConstant) + && (left.constant.typeID() == T_long) + && (left.constant.longValue() == 0L)) { + right.generateCode(currentScope, codeStream, false); + if (valueRequired) + codeStream.lconst_0(); + } else { + // x & 0 + if ((right.constant != Constant.NotAConstant) + && (right.constant.typeID() == T_long) + && (right.constant.longValue() == 0L)) { + left.generateCode(currentScope, codeStream, false); + if (valueRequired) + codeStream.lconst_0(); + } else { + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.land(); + } + } + break; + case T_boolean : // logical and + generateOptimizedLogicalAnd( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + valueRequired); + /* improving code gen for such a case: boolean b = i < 0 && false; + * since the label has never been used, we have the inlined value on the stack. */ + if (falseLabel.hasForwardReferences()) { + if (valueRequired) { + codeStream.iconst_1(); + if ((bits & ValueForReturnMASK) != 0) { + codeStream.ireturn(); + falseLabel.place(); + codeStream.iconst_0(); + } else { + codeStream.goto_(endLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + falseLabel.place(); + codeStream.iconst_0(); + endLabel.place(); + } + } else { + falseLabel.place(); + } + } + } + break; + case OR : + switch (bits & ReturnTypeIDMASK) { + case T_int : + // 0 | x + if ((left.constant != Constant.NotAConstant) + && (left.constant.typeID() == T_int) + && (left.constant.intValue() == 0)) { + right.generateCode(currentScope, codeStream, valueRequired); + } else { + // x | 0 + if ((right.constant != Constant.NotAConstant) + && (right.constant.typeID() == T_int) + && (right.constant.intValue() == 0)) { + left.generateCode(currentScope, codeStream, valueRequired); + } else { + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.ior(); + } + } + break; + case T_long : + // 0 | x + if ((left.constant != Constant.NotAConstant) + && (left.constant.typeID() == T_long) + && (left.constant.longValue() == 0L)) { + right.generateCode(currentScope, codeStream, valueRequired); + } else { + // x | 0 + if ((right.constant != Constant.NotAConstant) + && (right.constant.typeID() == T_long) + && (right.constant.longValue() == 0L)) { + left.generateCode(currentScope, codeStream, valueRequired); + } else { + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.lor(); + } + } + break; + case T_boolean : // logical or + generateOptimizedLogicalOr( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + valueRequired); + /* improving code gen for such a case: boolean b = i < 0 || true; + * since the label has never been used, we have the inlined value on the stack. */ + if (falseLabel.hasForwardReferences()) { + if (valueRequired) { + codeStream.iconst_1(); + if ((bits & ValueForReturnMASK) != 0) { + codeStream.ireturn(); + falseLabel.place(); + codeStream.iconst_0(); + } else { + codeStream.goto_(endLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + falseLabel.place(); + codeStream.iconst_0(); + endLabel.place(); + } + } else { + falseLabel.place(); + } + } + } + break; + case XOR : + switch (bits & ReturnTypeIDMASK) { + case T_int : + // 0 ^ x + if ((left.constant != Constant.NotAConstant) + && (left.constant.typeID() == T_int) + && (left.constant.intValue() == 0)) { + right.generateCode(currentScope, codeStream, valueRequired); + } else { + // x ^ 0 + if ((right.constant != Constant.NotAConstant) + && (right.constant.typeID() == T_int) + && (right.constant.intValue() == 0)) { + left.generateCode(currentScope, codeStream, valueRequired); + } else { + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.ixor(); + } + } + break; + case T_long : + // 0 ^ x + if ((left.constant != Constant.NotAConstant) + && (left.constant.typeID() == T_long) + && (left.constant.longValue() == 0L)) { + right.generateCode(currentScope, codeStream, valueRequired); + } else { + // x ^ 0 + if ((right.constant != Constant.NotAConstant) + && (right.constant.typeID() == T_long) + && (right.constant.longValue() == 0L)) { + left.generateCode(currentScope, codeStream, valueRequired); + } else { + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.lxor(); + } + } + break; + case T_boolean : + generateOptimizedLogicalXor( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + valueRequired); + /* improving code gen for such a case: boolean b = i < 0 ^ bool; + * since the label has never been used, we have the inlined value on the stack. */ + if (falseLabel.hasForwardReferences()) { + if (valueRequired) { + codeStream.iconst_1(); + if ((bits & ValueForReturnMASK) != 0) { + codeStream.ireturn(); + falseLabel.place(); + codeStream.iconst_0(); + } else { + codeStream.goto_(endLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + falseLabel.place(); + codeStream.iconst_0(); + endLabel.place(); + } + } else { + falseLabel.place(); + } + } + } + break; + case LEFT_SHIFT : + switch (bits & ReturnTypeIDMASK) { + case T_int : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.ishl(); + break; + case T_long : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.lshl(); + } + break; + case RIGHT_SHIFT : + switch (bits & ReturnTypeIDMASK) { + case T_int : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.ishr(); + break; + case T_long : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.lshr(); + } + break; + case UNSIGNED_RIGHT_SHIFT : + switch (bits & ReturnTypeIDMASK) { + case T_int : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.iushr(); + break; + case T_long : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.lushr(); + } + break; + case GREATER : + generateOptimizedGreaterThan( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + valueRequired); + if (valueRequired) { + codeStream.iconst_1(); + if ((bits & ValueForReturnMASK) != 0) { + codeStream.ireturn(); + falseLabel.place(); + codeStream.iconst_0(); + } else { + codeStream.goto_(endLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + falseLabel.place(); + codeStream.iconst_0(); + endLabel.place(); + } + } + break; + case GREATER_EQUAL : + generateOptimizedGreaterThanOrEqual( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + valueRequired); + if (valueRequired) { + codeStream.iconst_1(); + if ((bits & ValueForReturnMASK) != 0) { + codeStream.ireturn(); + falseLabel.place(); + codeStream.iconst_0(); + } else { + codeStream.goto_(endLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + falseLabel.place(); + codeStream.iconst_0(); + endLabel.place(); + } + } + break; + case LESS : + generateOptimizedLessThan( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + valueRequired); + if (valueRequired) { + codeStream.iconst_1(); + if ((bits & ValueForReturnMASK) != 0) { + codeStream.ireturn(); + falseLabel.place(); + codeStream.iconst_0(); + } else { + codeStream.goto_(endLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + falseLabel.place(); + codeStream.iconst_0(); + endLabel.place(); + } + } + break; + case LESS_EQUAL : + generateOptimizedLessThanOrEqual( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + valueRequired); + if (valueRequired) { + codeStream.iconst_1(); + if ((bits & ValueForReturnMASK) != 0) { + codeStream.ireturn(); + falseLabel.place(); + codeStream.iconst_0(); + } else { + codeStream.goto_(endLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + falseLabel.place(); + codeStream.iconst_0(); + endLabel.place(); + } + } + } + if (valueRequired) { + codeStream.generateImplicitConversion(implicitConversion); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + /** + * Boolean operator code generation + * Optimized operations are: <, <=, >, >=, &, |, ^ + */ + public void generateOptimizedBoolean( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) { + super.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + return; + } + switch ((bits & OperatorMASK) >> OperatorSHIFT) { + case LESS : + generateOptimizedLessThan( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + return; + case LESS_EQUAL : + generateOptimizedLessThanOrEqual( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + return; + case GREATER : + generateOptimizedGreaterThan( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + return; + case GREATER_EQUAL : + generateOptimizedGreaterThanOrEqual( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + return; + case AND : + generateOptimizedLogicalAnd( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + return; + case OR : + generateOptimizedLogicalOr( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + return; + case XOR : + generateOptimizedLogicalXor( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + return; + } + super.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + + /** + * Boolean generation for > + */ + public void generateOptimizedGreaterThan( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + int pc = codeStream.position; + int promotedTypeID = left.implicitConversion >> 4; + // both sides got promoted in the same way + if (promotedTypeID == T_int) { + // 0 > x + if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) { + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicitly falling through the FALSE case + codeStream.iflt(trueLabel); + } + } else { + if (trueLabel == null) { + // implicitly falling through the TRUE case + codeStream.ifge(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + // x > 0 + if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) { + left.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicitly falling through the FALSE case + codeStream.ifgt(trueLabel); + } + } else { + if (trueLabel == null) { + // implicitly falling through the TRUE case + codeStream.ifle(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + } + // default comparison + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + switch (promotedTypeID) { + case T_int : + codeStream.if_icmpgt(trueLabel); + break; + case T_float : + codeStream.fcmpl(); + codeStream.ifgt(trueLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.ifgt(trueLabel); + break; + case T_double : + codeStream.dcmpl(); + codeStream.ifgt(trueLabel); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + } else { + if (trueLabel == null) { + // implicit falling through the TRUE case + switch (promotedTypeID) { + case T_int : + codeStream.if_icmple(falseLabel); + break; + case T_float : + codeStream.fcmpl(); + codeStream.ifle(falseLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.ifle(falseLabel); + break; + case T_double : + codeStream.dcmpl(); + codeStream.ifle(falseLabel); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + } + + /** + * Boolean generation for >= + */ + public void generateOptimizedGreaterThanOrEqual( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + int pc = codeStream.position; + int promotedTypeID = left.implicitConversion >> 4; + // both sides got promoted in the same way + if (promotedTypeID == T_int) { + // 0 >= x + if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) { + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicitly falling through the FALSE case + codeStream.ifle(trueLabel); + } + } else { + if (trueLabel == null) { + // implicitly falling through the TRUE case + codeStream.ifgt(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + // x >= 0 + if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) { + left.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicitly falling through the FALSE case + codeStream.ifge(trueLabel); + } + } else { + if (trueLabel == null) { + // implicitly falling through the TRUE case + codeStream.iflt(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + } + // default comparison + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + switch (promotedTypeID) { + case T_int : + codeStream.if_icmpge(trueLabel); + break; + case T_float : + codeStream.fcmpl(); + codeStream.ifge(trueLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.ifge(trueLabel); + break; + case T_double : + codeStream.dcmpl(); + codeStream.ifge(trueLabel); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + } else { + if (trueLabel == null) { + // implicit falling through the TRUE case + switch (promotedTypeID) { + case T_int : + codeStream.if_icmplt(falseLabel); + break; + case T_float : + codeStream.fcmpl(); + codeStream.iflt(falseLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.iflt(falseLabel); + break; + case T_double : + codeStream.dcmpl(); + codeStream.iflt(falseLabel); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + } + + /** + * Boolean generation for < + */ + public void generateOptimizedLessThan( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + int pc = codeStream.position; + int promotedTypeID = left.implicitConversion >> 4; + // both sides got promoted in the same way + if (promotedTypeID == T_int) { + // 0 < x + if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) { + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicitly falling through the FALSE case + codeStream.ifgt(trueLabel); + } + } else { + if (trueLabel == null) { + // implicitly falling through the TRUE case + codeStream.ifle(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + // x < 0 + if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) { + left.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicitly falling through the FALSE case + codeStream.iflt(trueLabel); + } + } else { + if (trueLabel == null) { + // implicitly falling through the TRUE case + codeStream.ifge(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + } + // default comparison + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + switch (promotedTypeID) { + case T_int : + codeStream.if_icmplt(trueLabel); + break; + case T_float : + codeStream.fcmpg(); + codeStream.iflt(trueLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.iflt(trueLabel); + break; + case T_double : + codeStream.dcmpg(); + codeStream.iflt(trueLabel); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + } else { + if (trueLabel == null) { + // implicit falling through the TRUE case + switch (promotedTypeID) { + case T_int : + codeStream.if_icmpge(falseLabel); + break; + case T_float : + codeStream.fcmpg(); + codeStream.ifge(falseLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.ifge(falseLabel); + break; + case T_double : + codeStream.dcmpg(); + codeStream.ifge(falseLabel); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + } + + /** + * Boolean generation for <= + */ + public void generateOptimizedLessThanOrEqual( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + int pc = codeStream.position; + int promotedTypeID = left.implicitConversion >> 4; + // both sides got promoted in the same way + if (promotedTypeID == T_int) { + // 0 <= x + if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) { + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicitly falling through the FALSE case + codeStream.ifge(trueLabel); + } + } else { + if (trueLabel == null) { + // implicitly falling through the TRUE case + codeStream.iflt(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + // x <= 0 + if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) { + left.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicitly falling through the FALSE case + codeStream.ifle(trueLabel); + } + } else { + if (trueLabel == null) { + // implicitly falling through the TRUE case + codeStream.ifgt(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + } + // default comparison + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + switch (promotedTypeID) { + case T_int : + codeStream.if_icmple(trueLabel); + break; + case T_float : + codeStream.fcmpg(); + codeStream.ifle(trueLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.ifle(trueLabel); + break; + case T_double : + codeStream.dcmpg(); + codeStream.ifle(trueLabel); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + } else { + if (trueLabel == null) { + // implicit falling through the TRUE case + switch (promotedTypeID) { + case T_int : + codeStream.if_icmpgt(falseLabel); + break; + case T_float : + codeStream.fcmpg(); + codeStream.ifgt(falseLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.ifgt(falseLabel); + break; + case T_double : + codeStream.dcmpg(); + codeStream.ifgt(falseLabel); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + } + + /** + * Boolean generation for & + */ + public void generateOptimizedLogicalAnd( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + int pc = codeStream.position; + Constant condConst; + if ((left.implicitConversion & 0xF) == T_boolean) { + if ((condConst = left.conditionalConstant()) != NotAConstant) { + if (condConst.booleanValue() == true) { + // & x + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if ((bits & OnlyValueRequiredMASK) != 0) { + right.generateCode(currentScope, codeStream, valueRequired); + } else { + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + } else { + // & x + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if (valueRequired) { + if ((bits & OnlyValueRequiredMASK) != 0) { + codeStream.iconst_0(); + } else { + if (falseLabel != null) { + // implicit falling through the TRUE case + codeStream.goto_(falseLabel); + } + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + if ((condConst = right.conditionalConstant()) != NotAConstant) { + if (condConst.booleanValue() == true) { + // x & + if ((bits & OnlyValueRequiredMASK) != 0) { + left.generateCode(currentScope, codeStream, valueRequired); + } else { + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + } else { + // x & + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if (valueRequired) { + if ((bits & OnlyValueRequiredMASK) != 0) { + codeStream.iconst_0(); + } else { + if (falseLabel != null) { + // implicit falling through the TRUE case + codeStream.goto_(falseLabel); + } + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + } + // default case + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + codeStream.iand(); + if ((bits & OnlyValueRequiredMASK) == 0) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + codeStream.ifne(trueLabel); + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.ifeq(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + /** + * Boolean generation for | + */ + public void generateOptimizedLogicalOr( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + int pc = codeStream.position; + Constant condConst; + if ((left.implicitConversion & 0xF) == T_boolean) { + if ((condConst = left.conditionalConstant()) != NotAConstant) { + if (condConst.booleanValue() == true) { + // | x + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if (valueRequired) { + if ((bits & OnlyValueRequiredMASK) != 0) { + codeStream.iconst_1(); + } else { + if (trueLabel != null) { + codeStream.goto_(trueLabel); + } + } + } + } else { + // | x + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if ((bits & OnlyValueRequiredMASK) != 0) { + right.generateCode(currentScope, codeStream, valueRequired); + } else { + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + if ((condConst = right.conditionalConstant()) != NotAConstant) { + if (condConst.booleanValue() == true) { + // x | + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if (valueRequired) { + if ((bits & OnlyValueRequiredMASK) != 0) { + codeStream.iconst_1(); + } else { + if (trueLabel != null) { + codeStream.goto_(trueLabel); + } + } + } + } else { + // x | + if ((bits & OnlyValueRequiredMASK) != 0) { + left.generateCode(currentScope, codeStream, valueRequired); + } else { + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + } + // default case + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + codeStream.ior(); + if ((bits & OnlyValueRequiredMASK) == 0) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + codeStream.ifne(trueLabel); + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.ifeq(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + /** + * Boolean generation for ^ + */ + public void generateOptimizedLogicalXor( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + int pc = codeStream.position; + Constant condConst; + if ((left.implicitConversion & 0xF) == T_boolean) { + if ((condConst = left.conditionalConstant()) != NotAConstant) { + if (condConst.booleanValue() == true) { + // ^ x + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + right.generateOptimizedBoolean( + currentScope, + codeStream, + falseLabel, + trueLabel, + valueRequired); + } else { + // ^ x + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if ((bits & OnlyValueRequiredMASK) != 0) { + right.generateCode(currentScope, codeStream, valueRequired); + } else { + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + if ((condConst = right.conditionalConstant()) != NotAConstant) { + if (condConst.booleanValue() == true) { + // x ^ + left.generateOptimizedBoolean( + currentScope, + codeStream, + falseLabel, + trueLabel, + valueRequired); + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + } else { + // x ^ + if ((bits & OnlyValueRequiredMASK) != 0) { + left.generateCode(currentScope, codeStream, valueRequired); + } else { + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + } + // default case + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + codeStream.ixor(); + if ((bits & OnlyValueRequiredMASK) == 0) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + codeStream.ifne(trueLabel); + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.ifeq(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public void generateOptimizedStringBuffer( + BlockScope blockScope, + CodeStream codeStream, + int typeID) { + + /* In the case trying to make a string concatenation, there is no need to create a new + * string buffer, thus use a lower-level API for code generation involving only the + * appending of arguments to the existing StringBuffer + */ + + if ((((bits & OperatorMASK) >> OperatorSHIFT) == PLUS) + && ((bits & ReturnTypeIDMASK) == T_String)) { + if (constant != NotAConstant) { + codeStream.generateConstant(constant, implicitConversion); + codeStream.invokeStringBufferAppendForType(implicitConversion & 0xF); + } else { + int pc = codeStream.position; + left.generateOptimizedStringBuffer( + blockScope, + codeStream, + left.implicitConversion & 0xF); + codeStream.recordPositionsFrom(pc, left.sourceStart); + pc = codeStream.position; + right.generateOptimizedStringBuffer( + blockScope, + codeStream, + right.implicitConversion & 0xF); + codeStream.recordPositionsFrom(pc, right.sourceStart); + } + } else { + super.generateOptimizedStringBuffer(blockScope, codeStream, typeID); + } + } + + public void generateOptimizedStringBufferCreation( + BlockScope blockScope, + CodeStream codeStream, + int typeID) { + + /* In the case trying to make a string concatenation, there is no need to create a new + * string buffer, thus use a lower-level API for code generation involving only the + * appending of arguments to the existing StringBuffer + */ + + if ((((bits & OperatorMASK) >> OperatorSHIFT) == PLUS) + && ((bits & ReturnTypeIDMASK) == T_String)) { + if (constant != NotAConstant) { + codeStream.newStringBuffer(); // new: java.lang.StringBuffer + codeStream.dup(); + codeStream.ldc(constant.stringValue()); + codeStream.invokeStringBufferStringConstructor(); + // invokespecial: java.lang.StringBuffer.(Ljava.lang.String;)V + } else { + int pc = codeStream.position; + left.generateOptimizedStringBufferCreation( + blockScope, + codeStream, + left.implicitConversion & 0xF); + codeStream.recordPositionsFrom(pc, left.sourceStart); + pc = codeStream.position; + right.generateOptimizedStringBuffer( + blockScope, + codeStream, + right.implicitConversion & 0xF); + codeStream.recordPositionsFrom(pc, right.sourceStart); + } + } else { + super.generateOptimizedStringBufferCreation(blockScope, codeStream, typeID); + } + } + + public boolean isCompactableOperation() { + + return true; + } + + public void optimizedBooleanConstant(int leftId, int operator, int rightId) { + + switch (operator) { + case AND : + if ((leftId != T_boolean) || (rightId != T_boolean)) + return; + case AND_AND : + Constant cst; + if ((cst = left.conditionalConstant()) != NotAConstant) { + if (cst.booleanValue() == false) { // left is equivalent to false + optimizedBooleanConstant = cst; // constant(false) + return; + } else { //left is equivalent to true + if ((cst = right.conditionalConstant()) != NotAConstant) { + optimizedBooleanConstant = cst; + // the conditional result is equivalent to the right conditional value + } + return; + } + } + if ((cst = right.conditionalConstant()) != NotAConstant) { + if (cst.booleanValue() == false) { // right is equivalent to false + optimizedBooleanConstant = cst; // constant(false) + } + } + return; + case OR : + if ((leftId != T_boolean) || (rightId != T_boolean)) + return; + case OR_OR : + if ((cst = left.conditionalConstant()) != NotAConstant) { + if (cst.booleanValue() == true) { // left is equivalent to true + optimizedBooleanConstant = cst; // constant(true) + return; + } else { //left is equivalent to false + if ((cst = right.conditionalConstant()) != NotAConstant) { + optimizedBooleanConstant = cst; + } + return; + } + } + if ((cst = right.conditionalConstant()) != NotAConstant) { + if (cst.booleanValue() == true) { // right is equivalent to true + optimizedBooleanConstant = cst; // constant(true) + } + } + } + } + + public TypeBinding resolveType(BlockScope scope) { + + // use the id of the type to navigate into the table + TypeBinding leftTb = left.resolveType(scope); + TypeBinding rightTb = right.resolveType(scope); + if (leftTb == null || rightTb == null) { + constant = Constant.NotAConstant; + return null; + } + int leftId = leftTb.id; + int rightId = rightTb.id; + if (leftId > 15 + || rightId > 15) { // must convert String + Object || Object + String + if (leftId == T_String) { + rightId = T_Object; + } else if (rightId == T_String) { + leftId = T_Object; + } else { + constant = Constant.NotAConstant; + scope.problemReporter().invalidOperator(this, leftTb, rightTb); + return null; + } + } + if (((bits & OperatorMASK) >> OperatorSHIFT) == PLUS) { + if (leftId == T_String + && rightTb.isArrayType() + && ((ArrayBinding) rightTb).elementsType(scope) == CharBinding) + scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression( + right); + else if ( + rightId == T_String + && leftTb.isArrayType() + && ((ArrayBinding) leftTb).elementsType(scope) == CharBinding) + scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression( + left); + } + + // the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 <<0 + + // Don't test for result = 0. If it is zero, some more work is done. + // On the one hand when it is not zero (correct code) we avoid doing the test + int result = + ResolveTypeTables[(bits & OperatorMASK) >> OperatorSHIFT][(leftId << 4) + + rightId]; + left.implicitConversion = result >>> 12; + right.implicitConversion = (result >>> 4) & 0x000FF; + + bits |= result & 0xF; + switch (result & 0xF) { // record the current ReturnTypeID + // only switch on possible result type..... + case T_boolean : + this.typeBinding = BooleanBinding; + break; + case T_byte : + this.typeBinding = ByteBinding; + break; + case T_char : + this.typeBinding = CharBinding; + break; + case T_double : + this.typeBinding = DoubleBinding; + break; + case T_float : + this.typeBinding = FloatBinding; + break; + case T_int : + this.typeBinding = IntBinding; + break; + case T_long : + this.typeBinding = LongBinding; + break; + case T_String : + this.typeBinding = scope.getJavaLangString(); + break; + default : //error........ + constant = Constant.NotAConstant; + scope.problemReporter().invalidOperator(this, leftTb, rightTb); + return null; + } + + // compute the constant when valid + computeConstant(scope, leftId, rightId); + return this.typeBinding; + } + + public String toStringExpressionNoParenthesis() { + + return left.toStringExpression() + " " + //$NON-NLS-1$ + operatorToString() + " " + //$NON-NLS-1$ + right.toStringExpression(); + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + left.traverse(visitor, scope); + right.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Block.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Block.java new file mode 100644 index 0000000..2e00658 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Block.java @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class Block extends Statement { + + public Statement[] statements; + public int explicitDeclarations; + // the number of explicit declaration , used to create scope + public BlockScope scope; + public static final Block None = new Block(0); + + public Block(int explicitDeclarations) { + this.explicitDeclarations = explicitDeclarations; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // empty block + if (statements == null) + return flowInfo; + for (int i = 0, max = statements.length; i < max; i++) { + Statement stat; + if (!flowInfo.complainIfUnreachable((stat = statements[i]), scope)) { + flowInfo = stat.analyseCode(scope, flowContext, flowInfo); + } + } + return flowInfo; + } + + public static final Block EmptyWith(int sourceStart, int sourceEnd) { + + //return an empty block which position is s and e + Block bk = new Block(0); + bk.sourceStart = sourceStart; + bk.sourceEnd = sourceEnd; + return bk; + } + + /** + * Code generation for a block + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + if (statements != null) { + for (int i = 0, max = statements.length; i < max; i++) { + statements[i].generateCode(scope, codeStream); + } + } // for local variable debug attributes + if (scope != currentScope) { // was really associated with its own scope + codeStream.exitUserScope(scope); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public boolean isEmptyBlock() { + + return statements == null; + } + + public void resolve(BlockScope upperScope) { + + if (statements != null) { + scope = + explicitDeclarations == 0 + ? upperScope + : new BlockScope(upperScope, explicitDeclarations); + int i = 0, length = statements.length; + while (i < length) + statements[i++].resolve(scope); + } + } + + public void resolveUsing(BlockScope givenScope) { + + // this optimized resolve(...) is sent only on none empty blocks + scope = givenScope; + if (statements != null) { + int i = 0, length = statements.length; + while (i < length) + statements[i++].resolve(scope); + } + } + + public String toString(int tab) { + + String s = tabString(tab); + if (this.statements == null) { + s += "{\n"; //$NON-NLS-1$ + s += tabString(tab); + s += "}"; //$NON-NLS-1$ + return s; + } + s += "{\n"; //$NON-NLS-1$ + s += this.toStringStatements(tab); + s += tabString(tab); + s += "}"; //$NON-NLS-1$ + return s; + } + + public String toStringStatements(int tab) { + + if (this.statements == null) + return ""; //$NON-NLS-1$ + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < statements.length; i++) { + buffer.append(statements[i].toString(tab + 1)); + if (statements[i] instanceof Block) { + buffer.append("\n"); //$NON-NLS-1$ + } else { + buffer.append(";\n"); //$NON-NLS-1$ + } + }; + return buffer.toString(); + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + if (statements != null) { + int statementLength = statements.length; + for (int i = 0; i < statementLength; i++) + statements[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, blockScope); + } + + /** + * Dispatch the call on its last statement. + */ + public void branchChainTo(Label label) { + if (this.statements != null) { + this.statements[statements.length - 1].branchChainTo(label); + } + } + +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/BranchStatement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/BranchStatement.java new file mode 100644 index 0000000..b28486a --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/BranchStatement.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public abstract class BranchStatement extends Statement { + public char[] label; + public Label targetLabel; + public AstNode[] subroutines; +/** + * BranchStatement constructor comment. + */ +public BranchStatement(char[] l, int s,int e) { + label = l ; + sourceStart = s; + sourceEnd = e; +} +/** + * Branch code generation + * + * generate the finallyInvocationSequence. + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + + // generation of code responsible for invoking the finally + // blocks in sequence + if (subroutines != null){ + for (int i = 0, max = subroutines.length; i < max; i++){ + AstNode sub; + if ((sub = subroutines[i]) instanceof SynchronizedStatement){ + codeStream.load(((SynchronizedStatement)sub).synchroVariable); + codeStream.monitorexit(); + } else { + TryStatement trySub = (TryStatement) sub; + if (trySub.subRoutineCannotReturn) { + codeStream.goto_(trySub.subRoutineStartLabel); + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } else { + codeStream.jsr(trySub.subRoutineStartLabel); + } + } + } + } + codeStream.goto_(targetLabel); + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public void resetStateForCodeGeneration() { + this.targetLabel.resetStateForCodeGeneration(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Break.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Break.java new file mode 100644 index 0000000..8b3043e --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Break.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class Break extends BranchStatement { + + public Break(char[] label, int sourceStart, int e) { + super(label, sourceStart, e); + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // here requires to generate a sequence of finally blocks invocations depending corresponding + // to each of the traversed try statements, so that execution will terminate properly. + + // lookup the label, this should answer the returnContext + FlowContext targetContext; + if (label == null) { + targetContext = flowContext.getTargetContextForDefaultBreak(); + } else { + targetContext = flowContext.getTargetContextForBreakLabel(label); + } + if (targetContext == null) { + if (label == null) { + currentScope.problemReporter().invalidBreak(this); + } else { + currentScope.problemReporter().undefinedLabel(this); // need to improve + } + } else { + targetLabel = targetContext.breakLabel(); + targetContext.recordBreakFrom(flowInfo); + FlowContext traversedContext = flowContext; + int subIndex = 0, maxSub = 5; + subroutines = new AstNode[maxSub]; + while (true) { + AstNode sub; + if ((sub = traversedContext.subRoutine()) != null) { + if (subIndex == maxSub) { + System.arraycopy( + subroutines, + 0, + (subroutines = new AstNode[maxSub *= 2]), + 0, + subIndex); + // grow + } + subroutines[subIndex++] = sub; + if (sub.cannotReturn()) { + break; + } + } + // remember the initialization at this + // point for dealing with blank final variables. + traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); + + if (traversedContext == targetContext) { + break; + } else { + traversedContext = traversedContext.parent; + } + } + // resize subroutines + if (subIndex != maxSub) { + System.arraycopy( + subroutines, + 0, + (subroutines = new AstNode[subIndex]), + 0, + subIndex); + } + } + return FlowInfo.DeadEnd; + } + + public String toString(int tab) { + + String s = tabString(tab); + s = s + "break "; //$NON-NLS-1$ + if (label != null) + s = s + new String(label); + return s; + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + BlockScope blockscope) { + + visitor.visit(this, blockscope); + visitor.endVisit(this, blockscope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Case.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Case.java new file mode 100644 index 0000000..71d445f --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Case.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class Case extends Statement { + + public Expression constantExpression; + public CaseLabel targetLabel; + public Case(int sourceStart, Expression constantExpression) { + this.constantExpression = constantExpression; + this.sourceEnd = constantExpression.sourceEnd; + this.sourceStart = sourceStart; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + if (constantExpression.constant == NotAConstant) + currentScope.problemReporter().caseExpressionMustBeConstant(constantExpression); + + this.constantExpression.analyseCode(currentScope, flowContext, flowInfo); + return flowInfo; + } + + /** + * Case code generation + * + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + targetLabel.place(); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public void resolve(BlockScope scope) { + + // error....use resolveCase.... + throw new NullPointerException(); + } + + public Constant resolveCase( + BlockScope scope, + TypeBinding testTb, + SwitchStatement switchStatement) { + + // add into the collection of cases of the associated switch statement + switchStatement.cases[switchStatement.caseCount++] = this; + TypeBinding caseTb = constantExpression.resolveType(scope); + if (caseTb == null || testTb == null) + return null; + if (constantExpression.isConstantValueOfTypeAssignableToType(caseTb, testTb)) + return constantExpression.constant; + if (scope.areTypesCompatible(caseTb, testTb)) + return constantExpression.constant; + scope.problemReporter().typeMismatchErrorActualTypeExpectedType( + constantExpression, + caseTb, + testTb); + return null; + } + + public String toString(int tab) { + + String s = tabString(tab); + s = s + "case " + constantExpression.toStringExpression() + " : "; //$NON-NLS-1$ //$NON-NLS-2$ + return s; + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + constantExpression.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/CastExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/CastExpression.java new file mode 100644 index 0000000..f295b80 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/CastExpression.java @@ -0,0 +1,285 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class CastExpression extends Expression { + + public Expression expression; + public Expression type; + public boolean needRuntimeCheckcast; + public TypeBinding castTb; + + //expression.implicitConversion holds the cast for baseType casting + public CastExpression(Expression e, Expression t) { + expression = e; + type = t; + + //due to the fact an expression may start with ( and that a cast also start with ( + //the field is an expression....it can be a TypeReference OR a NameReference Or + //an expression <--this last one is invalid....... + + // :-( ............. + + //if (type instanceof TypeReference ) + // flag = IsTypeReference ; + //else + // if (type instanceof NameReference) + // flag = IsNameReference ; + // else + // flag = IsExpression ; + + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + return expression + .analyseCode(currentScope, flowContext, flowInfo) + .unconditionalInits(); + } + + public final void areTypesCastCompatible( + BlockScope scope, + TypeBinding castTb, + TypeBinding expressionTb) { + + // see specifications p.68 + // handle errors and process constant when needed + + // if either one of the type is null ==> + // some error has been already reported some where ==> + // we then do not report an obvious-cascade-error. + + needRuntimeCheckcast = false; + if (castTb == null || expressionTb == null) + return; + if (castTb.isBaseType()) { + if (expressionTb.isBaseType()) { + if (expressionTb == castTb) { + constant = expression.constant; //use the same constant + return; + } + if (scope.areTypesCompatible(expressionTb, castTb) + || BaseTypeBinding.isNarrowing(castTb.id, expressionTb.id)) { + expression.implicitConversion = (castTb.id << 4) + expressionTb.id; + if (expression.constant != Constant.NotAConstant) + constant = expression.constant.castTo(expression.implicitConversion); + return; + } + } + scope.problemReporter().typeCastError(this, castTb, expressionTb); + return; + } + + //-----------cast to something which is NOT a base type-------------------------- + if (expressionTb == NullBinding) + return; //null is compatible with every thing + + if (expressionTb.isBaseType()) { + scope.problemReporter().typeCastError(this, castTb, expressionTb); + return; + } + + if (expressionTb.isArrayType()) { + if (castTb.isArrayType()) { + //------- (castTb.isArray) expressionTb.isArray ----------- + TypeBinding expressionEltTb = ((ArrayBinding) expressionTb).elementsType(scope); + if (expressionEltTb.isBaseType()) { + // <---stop the recursion------- + if (((ArrayBinding) castTb).elementsType(scope) == expressionEltTb) + needRuntimeCheckcast = true; + else + scope.problemReporter().typeCastError(this, castTb, expressionTb); + return; + } + // recursively on the elements... + areTypesCastCompatible( + scope, + ((ArrayBinding) castTb).elementsType(scope), + expressionEltTb); + return; + } else if ( + castTb.isClass()) { + //------(castTb.isClass) expressionTb.isArray --------------- + if (scope.isJavaLangObject(castTb)) + return; + } else { //------- (castTb.isInterface) expressionTb.isArray ----------- + if (scope.isJavaLangCloneable(castTb) || scope.isJavaIoSerializable(castTb)) { + needRuntimeCheckcast = true; + return; + } + } + scope.problemReporter().typeCastError(this, castTb, expressionTb); + return; + } + + if (expressionTb.isClass()) { + if (castTb.isArrayType()) { + // ---- (castTb.isArray) expressionTb.isClass ------- + if (scope.isJavaLangObject(expressionTb)) { // potential runtime error + needRuntimeCheckcast = true; + return; + } + } else if ( + castTb.isClass()) { // ----- (castTb.isClass) expressionTb.isClass ------ + if (scope.areTypesCompatible(expressionTb, castTb)) // no runtime error + return; + if (scope.areTypesCompatible(castTb, expressionTb)) { + // potential runtime error + needRuntimeCheckcast = true; + return; + } + } else { // ----- (castTb.isInterface) expressionTb.isClass ------- + if (((ReferenceBinding) expressionTb).isFinal()) { + // no subclass for expressionTb, thus compile-time check is valid + if (scope.areTypesCompatible(expressionTb, castTb)) + return; + } else { // a subclass may implement the interface ==> no check at compile time + needRuntimeCheckcast = true; + return; + } + } + scope.problemReporter().typeCastError(this, castTb, expressionTb); + return; + } + + // if (expressionTb.isInterface()) { cannot be anything else + if (castTb.isArrayType()) { + // ----- (castTb.isArray) expressionTb.isInterface ------ + if (scope.isJavaLangCloneable(expressionTb) + || scope.isJavaIoSerializable(expressionTb)) // potential runtime error + needRuntimeCheckcast = true; + else + scope.problemReporter().typeCastError(this, castTb, expressionTb); + return; + } else if ( + castTb.isClass()) { // ----- (castTb.isClass) expressionTb.isInterface -------- + if (scope.isJavaLangObject(castTb)) // no runtime error + return; + if (((ReferenceBinding) castTb).isFinal()) { + // no subclass for castTb, thus compile-time check is valid + if (!scope.areTypesCompatible(castTb, expressionTb)) { + // potential runtime error + scope.problemReporter().typeCastError(this, castTb, expressionTb); + return; + } + } + } else { // ----- (castTb.isInterface) expressionTb.isInterface ------- + if (castTb != expressionTb + && (Scope.compareTypes(castTb, expressionTb) == NotRelated)) { + MethodBinding[] castTbMethods = ((ReferenceBinding) castTb).methods(); + MethodBinding[] expressionTbMethods = + ((ReferenceBinding) expressionTb).methods(); + int exprMethodsLength = expressionTbMethods.length; + for (int i = 0, castMethodsLength = castTbMethods.length; + i < castMethodsLength; + i++) + for (int j = 0; j < exprMethodsLength; j++) + if (castTbMethods[i].returnType != expressionTbMethods[j].returnType) + if (castTbMethods[i].selector == expressionTbMethods[j].selector) + if (castTbMethods[i].areParametersEqual(expressionTbMethods[j])) + scope.problemReporter().typeCastError(this, castTb, expressionTb); + } + } + needRuntimeCheckcast = true; + return; + } + + /** + * Cast expression code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + if (constant != NotAConstant) { + if (valueRequired + || needRuntimeCheckcast) { // Added for: 1F1W9IG: IVJCOM:WINNT - Compiler omits casting check + codeStream.generateConstant(constant, implicitConversion); + if (needRuntimeCheckcast) { + codeStream.checkcast(castTb); + if (!valueRequired) + codeStream.pop(); + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + expression.generateCode( + currentScope, + codeStream, + valueRequired || needRuntimeCheckcast); + if (needRuntimeCheckcast) { + codeStream.checkcast(castTb); + if (!valueRequired) + codeStream.pop(); + } else { + if (valueRequired) + codeStream.generateImplicitConversion(implicitConversion); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public TypeBinding resolveType(BlockScope scope) { + // compute a new constant if the cast is effective + + // due to the fact an expression may start with ( and that a cast can also start with ( + // the field is an expression....it can be a TypeReference OR a NameReference Or + // any kind of Expression <-- this last one is invalid....... + + constant = Constant.NotAConstant; + implicitConversion = T_undefined; + TypeBinding expressionTb = expression.resolveType(scope); + if (expressionTb == null) + return null; + + if ((type instanceof TypeReference) || (type instanceof NameReference)) { + if ((castTb = type.resolveType(scope)) == null) + return null; + areTypesCastCompatible(scope, castTb, expressionTb); + return castTb; + } else { // expression as a cast !!!!!!!! + scope.problemReporter().invalidTypeReference(type); + return null; + } + } + + public String toStringExpression() { + + return "(" + type.toString(0) + ") " + //$NON-NLS-2$ //$NON-NLS-1$ + expression.toStringExpression(); + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + type.traverse(visitor, blockScope); + expression.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/CharLiteral.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/CharLiteral.java new file mode 100644 index 0000000..40ef4fd --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/CharLiteral.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class CharLiteral extends NumberLiteral { + char value; +public CharLiteral(char[] token, int s, int e) { + super(token, s, e); + computeValue(); +} +public void computeConstant() { + //The source is a char[3] first and last char are ' + //This is true for both regular char AND unicode char + //BUT not for escape char like '\b' which are char[4].... + + constant = Constant.fromValue(value); +} +private void computeValue() { + //The source is a char[3] first and last char are ' + //This is true for both regular char AND unicode char + //BUT not for escape char like '\b' which are char[4].... + + if ((value = source[1]) != '\\') + return; + char digit; + switch (digit = source[2]) { + case 'b' : + value = '\b'; + break; + case 't' : + value = '\t'; + break; + case 'n' : + value = '\n'; + break; + case 'f' : + value = '\f'; + break; + case 'r' : + value = '\r'; + break; + case '\"' : + value = '\"'; + break; + case '\'' : + value = '\''; + break; + case '\\' : + value = '\\'; + break; + default : //octal (welled formed, i.e. ended by a ' ) + int number = Character.getNumericValue(digit); + if ((digit = source[3]) != '\'') + number = (number * 8) + Character.getNumericValue(digit); + else { + constant = Constant.fromValue(value = (char) number); + break; + }; + if ((digit = source[4]) != '\'') + number = (number * 8) + Character.getNumericValue(digit); + value = (char) number; + break; + } +} +/** + * CharLiteral code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + int pc = codeStream.position; + if (valueRequired) + if ((implicitConversion >> 4) == T_char) + codeStream.generateInlinedValue(value); + else + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public TypeBinding literalType(BlockScope scope) { + return CharBinding; +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope blockScope) { + visitor.visit(this, blockScope); + visitor.endVisit(this, blockScope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ClassLiteralAccess.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ClassLiteralAccess.java new file mode 100644 index 0000000..90e0e2a --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ClassLiteralAccess.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class ClassLiteralAccess extends Expression { + + public TypeReference type; + public TypeBinding targetType; + FieldBinding syntheticField; + + public ClassLiteralAccess(int sourceEnd, TypeReference t) { + type = t; + this.sourceStart = t.sourceStart; + this.sourceEnd = sourceEnd; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // if reachable, request the addition of a synthetic field for caching the class descriptor + SourceTypeBinding sourceType = + currentScope.outerMostMethodScope().enclosingSourceType(); + if (!(sourceType.isInterface() + // no field generated in interface case (would'nt verify) see 1FHHEZL + || sourceType.isBaseType())) { + syntheticField = sourceType.addSyntheticField(targetType, currentScope); + } + return flowInfo; + } + + /** + * MessageSendDotClass code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + int pc = codeStream.position; + + // in interface case, no caching occurs, since cannot make a cache field for interface + if (valueRequired) + codeStream.generateClassLiteralAccessForType(type.binding, syntheticField); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public TypeBinding resolveType(BlockScope scope) { + + constant = NotAConstant; + if ((targetType = type.resolveType(scope)) == null) + return null; + + if (targetType.isArrayType() + && ((ArrayBinding) targetType).leafComponentType == VoidBinding) { + scope.problemReporter().cannotAllocateVoidArray(this); + return null; + } + + return scope.getJavaLangClass(); + } + + public String toStringExpression() { + + String s = ""; //$NON-NLS-1$ + s = s + type.toString(0) + ".class"; //$NON-NLS-1$ + return s; + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + type.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Clinit.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Clinit.java new file mode 100644 index 0000000..3c4fe7b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Clinit.java @@ -0,0 +1,255 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.parser.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; + +public class Clinit extends AbstractMethodDeclaration { + + public final static char[] ConstantPoolName = "".toCharArray(); //$NON-NLS-1$ + + private FieldBinding assertionSyntheticFieldBinding = null; + private FieldBinding classLiteralSyntheticField = null; + + public Clinit(CompilationResult compilationResult) { + super(compilationResult); + modifiers = 0; + selector = ConstantPoolName; + } + + public void analyseCode( + ClassScope classScope, + InitializationFlowContext staticInitializerFlowContext, + FlowInfo flowInfo) { + + if (ignoreFurtherInvestigation) + return; + try { + ExceptionHandlingFlowContext clinitContext = + new ExceptionHandlingFlowContext( + staticInitializerFlowContext.parent, + this, + NoExceptions, + scope, + FlowInfo.DeadEnd); + + // check for missing returning path + needFreeReturn = + !((flowInfo == FlowInfo.DeadEnd) || flowInfo.isFakeReachable()); + + // check missing blank final field initializations + flowInfo = flowInfo.mergedWith(staticInitializerFlowContext.initsOnReturn); + FieldBinding[] fields = scope.enclosingSourceType().fields(); + for (int i = 0, count = fields.length; i < count; i++) { + FieldBinding field; + if ((field = fields[i]).isStatic() + && field.isFinal() + && (!flowInfo.isDefinitelyAssigned(fields[i]))) { + scope.problemReporter().uninitializedBlankFinalField( + field, + scope.referenceType().declarationOf(field)); + // can complain against the field decl, since only one + } + } + // check static initializers thrown exceptions + staticInitializerFlowContext.checkInitializerExceptions( + scope, + clinitContext, + flowInfo); + } catch (AbortMethod e) { + this.ignoreFurtherInvestigation = true; + } + } + + /** + * Bytecode generation for a method + * + * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope + * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile + */ + public void generateCode(ClassScope classScope, ClassFile classFile) { + + int clinitOffset = 0; + if (ignoreFurtherInvestigation) { + // should never have to add any problem method + return; + } + try { + clinitOffset = classFile.contentsOffset; + this.generateCode(classScope, classFile, clinitOffset); + } catch (AbortMethod e) { + // should never occur + // the clinit referenceContext is the type declaration + // All clinit problems will be reported against the type: AbortType instead of AbortMethod + // reset the contentsOffset to the value before generating the clinit code + // decrement the number of method info as well. + // This is done in the addProblemMethod and addProblemConstructor for other + // cases. + if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) { + // a branch target required a goto_w, restart code gen in wide mode. + try { + if (statements != null) { + for (int i = 0, max = statements.length; i < max; i++) + statements[i].resetStateForCodeGeneration(); + } + classFile.contentsOffset = clinitOffset; + classFile.methodCount--; + classFile.codeStream.wideMode = true; // request wide mode + this.generateCode(classScope, classFile, clinitOffset); + // restart method generation + } catch (AbortMethod e2) { + classFile.contentsOffset = clinitOffset; + classFile.methodCount--; + } + } else { + // produce a problem method accounting for this fatal error + classFile.contentsOffset = clinitOffset; + classFile.methodCount--; + } + } + } + + /** + * Bytecode generation for a method + * + * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope + * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile + */ + private void generateCode( + ClassScope classScope, + ClassFile classFile, + int clinitOffset) { + + ConstantPool constantPool = classFile.constantPool; + int constantPoolOffset = constantPool.currentOffset; + int constantPoolIndex = constantPool.currentIndex; + classFile.generateMethodInfoHeaderForClinit(); + int codeAttributeOffset = classFile.contentsOffset; + classFile.generateCodeAttributeHeader(); + CodeStream codeStream = classFile.codeStream; + this.resolve(classScope); + + codeStream.reset(this, classFile); + TypeDeclaration declaringType = classScope.referenceContext; + + // initialize local positions - including initializer scope. + scope.computeLocalVariablePositions(0, codeStream); // should not be necessary + MethodScope staticInitializerScope = declaringType.staticInitializerScope; + staticInitializerScope.computeLocalVariablePositions(0, codeStream); + // offset by the argument size + + // 1.4 feature + // This has to be done before any other initialization + if (this.assertionSyntheticFieldBinding != null) { + // generate code related to the activation of assertion for this class + codeStream.generateClassLiteralAccessForType( + classScope.enclosingSourceType(), + classLiteralSyntheticField); + codeStream.invokeJavaLangClassDesiredAssertionStatus(); + Label falseLabel = new Label(codeStream); + codeStream.ifne(falseLabel); + codeStream.iconst_1(); + Label jumpLabel = new Label(codeStream); + codeStream.goto_(jumpLabel); + falseLabel.place(); + codeStream.iconst_0(); + jumpLabel.place(); + codeStream.putstatic(this.assertionSyntheticFieldBinding); + } + // generate initializers + if (declaringType.fields != null) { + for (int i = 0, max = declaringType.fields.length; i < max; i++) { + FieldDeclaration fieldDecl; + if ((fieldDecl = declaringType.fields[i]).isStatic()) { + fieldDecl.generateCode(staticInitializerScope, codeStream); + } + } + } + if (codeStream.position == 0) { + // do not need to output a Clinit if no bytecodes + // so we reset the offset inside the byte array contents. + classFile.contentsOffset = clinitOffset; + // like we don't addd a method we need to undo the increment on the method count + classFile.methodCount--; + // reset the constant pool to its state before the clinit + constantPool.resetForClinit(constantPoolIndex, constantPoolOffset); + } else { + if (needFreeReturn) { + int oldPosition = codeStream.position; + codeStream.return_(); + codeStream.updateLocalVariablesAttribute(oldPosition); + } + // Record the end of the clinit: point to the declaration of the class + codeStream.recordPositionsFrom(0, declaringType.sourceStart); + classFile.completeCodeAttributeForClinit(codeAttributeOffset); + } + } + + public boolean isClinit() { + + return true; + } + + public boolean isInitializationMethod() { + + return true; + } + + public boolean isStatic() { + + return true; + } + + public void parseStatements(Parser parser, CompilationUnitDeclaration unit) { + //the clinit is filled by hand .... + } + + public void resolve(ClassScope scope) { + + this.scope = new MethodScope(scope, scope.referenceContext, true); + } + + public String toString(int tab) { + + String s = ""; //$NON-NLS-1$ + s = s + tabString(tab); + s = s + "()"; //$NON-NLS-1$ + s = s + toStringStatements(tab + 1); + return s; + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + ClassScope classScope) { + + visitor.visit(this, classScope); + visitor.endVisit(this, classScope); + } + + // 1.4 feature + public void addSupportForAssertion(FieldBinding assertionSyntheticFieldBinding) { + + this.assertionSyntheticFieldBinding = assertionSyntheticFieldBinding; + + // we need to add the field right now, because the field infos are generated before the methods + SourceTypeBinding sourceType = + this.scope.outerMostMethodScope().enclosingSourceType(); + this.classLiteralSyntheticField = + sourceType.addSyntheticField(sourceType, scope); + } + +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/CompilationUnitDeclaration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/CompilationUnitDeclaration.java new file mode 100644 index 0000000..f05ef3e --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/CompilationUnitDeclaration.java @@ -0,0 +1,290 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.*; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; +import net.sourceforge.phpdt.internal.compiler.util.*; + +public class CompilationUnitDeclaration + extends AstNode + implements ProblemSeverities, ReferenceContext { + + public ImportReference currentPackage; + public ImportReference[] imports; + public TypeDeclaration[] types; + //public char[][] name; + + public boolean ignoreFurtherInvestigation = false; // once pointless to investigate due to errors + public boolean ignoreMethodBodies = false; + public CompilationUnitScope scope; + public ProblemReporter problemReporter; + public CompilationResult compilationResult; + + private LocalTypeBinding[] allLocalTypes; + public boolean isPropagatingInnerClassEmulation; + + public CompilationUnitDeclaration( + ProblemReporter problemReporter, + CompilationResult compilationResult, + int sourceLength) { + + this.problemReporter = problemReporter; + this.compilationResult = compilationResult; + + //by definition of a compilation unit.... + sourceStart = 0; + sourceEnd = sourceLength - 1; + + } + + /* + * We cause the compilation task to abort to a given extent. + */ + public void abort(int abortLevel) { + + switch (abortLevel) { + case AbortType : + throw new AbortType(compilationResult); + case AbortMethod : + throw new AbortMethod(compilationResult); + default : + throw new AbortCompilationUnit(compilationResult); + } + } + + /* + * Dispatch code analysis AND request saturation of inner emulation + */ + public void analyseCode() { + + if (ignoreFurtherInvestigation) + return; + try { + if (types != null) { + for (int i = 0, count = types.length; i < count; i++) { + types[i].analyseCode(scope); + } + } + // request inner emulation propagation + propagateInnerEmulationForAllLocalTypes(); + } catch (AbortCompilationUnit e) { + this.ignoreFurtherInvestigation = true; + return; + } + } + + /* + * When unit result is about to be accepted, removed back pointers + * to compiler structures. + */ + public void cleanUp() { + + ClassFile[] classFiles = compilationResult.getClassFiles(); + for (int i = 0, max = classFiles.length; i < max; i++) { + // clear the classFile back pointer to the bindings + ClassFile classFile = classFiles[i]; + // null out the type's scope backpointers + ((SourceTypeBinding) classFile.referenceBinding).scope = null; + // null out the classfile backpointer to a type binding + classFile.referenceBinding = null; + classFile.codeStream = null; // codeStream holds onto ast and scopes + classFile.innerClassesBindings = null; + } + } + + public void checkUnusedImports(){ + + if (this.scope.imports != null){ + for (int i = 0, max = this.scope.imports.length; i < max; i++){ + ImportBinding importBinding = this.scope.imports[i]; + ImportReference importReference = importBinding.reference; + if (importReference != null && !importReference.used){ + scope.problemReporter().unusedImport(importReference); + } + } + } + } + + public CompilationResult compilationResult() { + return compilationResult; + } + + /* + * Finds the matching type amoung this compilation unit types. + * Returns null if no type with this name is found. + * The type name is a compound name + * eg. if we're looking for X.A.B then a type name would be {X, A, B} + */ + public TypeDeclaration declarationOfType(char[][] typeName) { + + for (int i = 0; i < this.types.length; i++) { + TypeDeclaration typeDecl = this.types[i].declarationOfType(typeName); + if (typeDecl != null) { + return typeDecl; + } + } + return null; + } + + /** + * Bytecode generation + */ + public void generateCode() { + + if (ignoreFurtherInvestigation) { + if (types != null) { + for (int i = 0, count = types.length; i < count; i++) { + types[i].ignoreFurtherInvestigation = true; + // propagate the flag to request problem type creation + types[i].generateCode(scope); + } + } + return; + } + try { + if (types != null) { + for (int i = 0, count = types.length; i < count; i++) + types[i].generateCode(scope); + } + } catch (AbortCompilationUnit e) { + } + } + + public char[] getFileName() { + + return compilationResult.getFileName(); + } + + public char[] getMainTypeName() { + + if (compilationResult.compilationUnit == null) { + char[] fileName = compilationResult.getFileName(); + + int start = CharOperation.lastIndexOf('/', fileName) + 1; + if (start == 0 || start < CharOperation.lastIndexOf('\\', fileName)) + start = CharOperation.lastIndexOf('\\', fileName) + 1; + + int end = CharOperation.lastIndexOf('.', fileName); + if (end == -1) + end = fileName.length; + + return CharOperation.subarray(fileName, start, end); + } else { + return compilationResult.compilationUnit.getMainTypeName(); + } + } + + public boolean isEmpty() { + + return (currentPackage == null) && (imports == null) && (types == null); + } + + public boolean hasErrors() { + return this.ignoreFurtherInvestigation; + } + + /* + * Force inner local types to update their innerclass emulation + */ + public void propagateInnerEmulationForAllLocalTypes() { + + isPropagatingInnerClassEmulation = true; + if (allLocalTypes != null) { + for (int i = 0, max = allLocalTypes.length; i < max; i++) { + allLocalTypes[i].updateInnerEmulationDependents(); + } + } + } + + /* + * Keep track of all local types, so as to update their innerclass + * emulation later on. + */ + public void record(LocalTypeBinding localType) { + + if (allLocalTypes == null) { + allLocalTypes = new LocalTypeBinding[] { localType }; + } else { + int length = allLocalTypes.length; + System.arraycopy( + allLocalTypes, + 0, + (allLocalTypes = new LocalTypeBinding[length + 1]), + 0, + length); + allLocalTypes[length] = localType; + } + } + + public void resolve() { + + try { + if (types != null) { + for (int i = 0, count = types.length; i < count; i++) { + types[i].resolve(scope); + } + } + checkUnusedImports(); + } catch (AbortCompilationUnit e) { + this.ignoreFurtherInvestigation = true; + return; + } + } + + public void tagAsHavingErrors() { + ignoreFurtherInvestigation = true; + } + + public String toString(int tab) { + + String s = ""; //$NON-NLS-1$ + if (currentPackage != null) + s = tabString(tab) + "package " + currentPackage.toString(0, false) + ";\n"; //$NON-NLS-1$ //$NON-NLS-2$ + + if (imports != null) + for (int i = 0; i < imports.length; i++) { + s += tabString(tab) + "import " + imports[i].toString() + ";\n"; //$NON-NLS-1$ //$NON-NLS-2$ + }; + + if (types != null) + for (int i = 0; i < types.length; i++) { + s += types[i].toString(tab) + "\n"; //$NON-NLS-1$ + } + return s; + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + CompilationUnitScope scope) { + + if (ignoreFurtherInvestigation) + return; + try { + if (visitor.visit(this, scope)) { + if (imports != null) { + int importLength = imports.length; + for (int i = 0; i < importLength; i++) + imports[i].traverse(visitor, scope); + } + if (types != null) { + int typesLength = types.length; + for (int i = 0; i < typesLength; i++) + types[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, scope); + } catch (AbortCompilationUnit e) { + } + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/CompoundAssignment.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/CompoundAssignment.java new file mode 100644 index 0000000..4dd83aa --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/CompoundAssignment.java @@ -0,0 +1,141 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class CompoundAssignment extends Assignment implements OperatorIds { + public int operator; + public int assignmentImplicitConversion; + + // var op exp is equivalent to var = (varType) var op exp + // assignmentImplicitConversion stores the cast needed for the assignment + +public CompoundAssignment(Expression lhs, Expression expression,int operator, int sourceEnd) { + //lhs is always a reference by construction , + //but is build as an expression ==> the checkcast cannot fail + + super(lhs, expression, sourceEnd); + this.operator = operator ; +} +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + // record setting a variable: various scenarii are possible, setting an array reference, + // a field reference, a blank final field reference, a field of an enclosing instance or + // just a local variable. + + return lhs.analyseAssignment(currentScope, flowContext, flowInfo, this, true).unconditionalInits(); +} +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + + // various scenarii are possible, setting an array reference, + // a field reference, a blank final field reference, a field of an enclosing instance or + // just a local variable. + + int pc = codeStream.position; + lhs.generateCompoundAssignment(currentScope, codeStream, expression, operator, assignmentImplicitConversion, valueRequired); + if (valueRequired) { + codeStream.generateImplicitConversion(implicitConversion); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public String operatorToString() { + switch (operator) { + case PLUS : + return "+="; //$NON-NLS-1$ + case MINUS : + return "-="; //$NON-NLS-1$ + case MULTIPLY : + return "*="; //$NON-NLS-1$ + case DIVIDE : + return "/="; //$NON-NLS-1$ + case AND : + return "&="; //$NON-NLS-1$ + case OR : + return "|="; //$NON-NLS-1$ + case XOR : + return "^="; //$NON-NLS-1$ + case REMAINDER : + return "%="; //$NON-NLS-1$ + case LEFT_SHIFT : + return "<<="; //$NON-NLS-1$ + case RIGHT_SHIFT : + return ">>="; //$NON-NLS-1$ + case UNSIGNED_RIGHT_SHIFT : + return ">>>="; //$NON-NLS-1$ + }; + return "unknown operator"; //$NON-NLS-1$ +} +public TypeBinding resolveType(BlockScope scope) { + constant = NotAConstant; + TypeBinding lhsType = lhs.resolveType(scope); + TypeBinding expressionType = expression.resolveType(scope); + if (lhsType == null || expressionType == null) + return null; + + int lhsId = lhsType.id; + int expressionId = expressionType.id; + if (restrainUsageToNumericTypes() && !lhsType.isNumericType()) { + scope.problemReporter().operatorOnlyValidOnNumericType(this, lhsType, expressionType); + return null; + } + if (lhsId > 15 || expressionId > 15) { + if (lhsId != T_String) { // String += Object is valid wheraas Object -= String is not + scope.problemReporter().invalidOperator(this, lhsType, expressionType); + return null; + } + expressionId = T_Object; // use the Object has tag table + } + + // the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 <<0 + + // the conversion is stored INTO the reference (info needed for the code gen) + int result = OperatorExpression.ResolveTypeTables[operator][ (lhsId << 4) + expressionId]; + if (result == T_undefined) { + scope.problemReporter().invalidOperator(this, lhsType, expressionType); + return null; + } + if (operator == PLUS){ + if(scope.isJavaLangObject(lhsType)) { + // += is illegal + scope.problemReporter().invalidOperator(this, lhsType, expressionType); + return null; + } else if ((lhsType.isNumericType() || lhsId == T_boolean) && !expressionType.isNumericType()){ + // += is illegal + scope.problemReporter().invalidOperator(this, lhsType, expressionType); + return null; + } + } + lhs.implicitConversion = result >>> 12; + expression.implicitConversion = (result >>> 4) & 0x000FF; + assignmentImplicitConversion = (lhsId << 4) + (result & 0x0000F); + return lhsType; +} +public boolean restrainUsageToNumericTypes(){ + return false ;} +public String toStringExpressionNoParenthesis() { + + return lhs.toStringExpression() + " " + //$NON-NLS-1$ + operatorToString() + " " + //$NON-NLS-1$ + expression.toStringExpression() ; } +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + if (visitor.visit(this, scope)) { + lhs.traverse(visitor, scope); + expression.traverse(visitor, scope); + } + visitor.endVisit(this, scope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ConditionalExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ConditionalExpression.java new file mode 100644 index 0000000..d234618 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ConditionalExpression.java @@ -0,0 +1,413 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class ConditionalExpression extends OperatorExpression { + + public Expression condition, valueIfTrue, valueIfFalse; + private int returnTypeSlotSize = 1; + + // for local variables table attributes + int thenInitStateIndex = -1; + int elseInitStateIndex = -1; + int mergedInitStateIndex = -1; + + public ConditionalExpression( + Expression condition, + Expression valueIfTrue, + Expression valueIfFalse) { + this.condition = condition; + this.valueIfTrue = valueIfTrue; + this.valueIfFalse = valueIfFalse; + sourceStart = condition.sourceStart; + sourceEnd = valueIfFalse.sourceEnd; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + Constant conditionConstant = condition.conditionalConstant(); + + flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo, conditionConstant == NotAConstant); + + if (conditionConstant != NotAConstant) { + if (conditionConstant.booleanValue() == true) { + // TRUE ? left : right + FlowInfo resultInfo = + valueIfTrue.analyseCode(currentScope, flowContext, flowInfo.initsWhenTrue().unconditionalInits()); + // analyse valueIfFalse, but do not take into account any of its infos + valueIfFalse.analyseCode( + currentScope, + flowContext, + flowInfo.initsWhenFalse().copy().unconditionalInits().markAsFakeReachable(true)); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(resultInfo); + return resultInfo; + } else { + // FALSE ? left : right + // analyse valueIfTrue, but do not take into account any of its infos + valueIfTrue.analyseCode( + currentScope, + flowContext, + flowInfo.initsWhenTrue().copy().unconditionalInits().markAsFakeReachable(true)); + FlowInfo mergeInfo = + valueIfFalse.analyseCode(currentScope, flowContext, flowInfo.initsWhenFalse().unconditionalInits()); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergeInfo); + return mergeInfo; + } + } + + // store a copy of the merged info, so as to compute the local variable attributes afterwards + FlowInfo trueInfo = flowInfo.initsWhenTrue(); + thenInitStateIndex = + currentScope.methodScope().recordInitializationStates(trueInfo); + FlowInfo falseInfo = flowInfo.initsWhenFalse(); + elseInitStateIndex = + currentScope.methodScope().recordInitializationStates(falseInfo); + + // propagate analysis + trueInfo = valueIfTrue.analyseCode(currentScope, flowContext, trueInfo.copy()); + falseInfo = + valueIfFalse.analyseCode(currentScope, flowContext, falseInfo.copy()); + + // merge back using a conditional info - 1GK2BLM + // if ((t && (v = t)) ? t : t && (v = f)) r = v; -- ok + FlowInfo mergedInfo = + FlowInfo.conditional( + trueInfo.initsWhenTrue().copy().unconditionalInits().mergedWith( // must copy, since could be shared with trueInfo.initsWhenFalse()... + falseInfo.initsWhenTrue().copy().unconditionalInits()), + trueInfo.initsWhenFalse().unconditionalInits().mergedWith( + falseInfo.initsWhenFalse().unconditionalInits())); + /* + FlowInfo mergedInfo = valueIfTrue.analyseCode( + currentScope, + flowContext, + flowInfo.initsWhenTrue().copy()). + unconditionalInits(). + mergedWith( + valueIfFalse.analyseCode( + currentScope, + flowContext, + flowInfo.initsWhenFalse().copy()). + unconditionalInits()); + */ + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + + /** + * Code generation for the conditional operator ?: + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + Label endifLabel, falseLabel; + if (constant != NotAConstant) { + if (valueRequired) + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + Constant cst = condition.constant; + Constant condCst = condition.conditionalConstant(); + boolean needTruePart = + !(((cst != NotAConstant) && (cst.booleanValue() == false)) + || ((condCst != NotAConstant) && (condCst.booleanValue() == false))); + boolean needFalsePart = + !(((cst != NotAConstant) && (cst.booleanValue() == true)) + || ((condCst != NotAConstant) && (condCst.booleanValue() == true))); + endifLabel = new Label(codeStream); + + // Generate code for the condition + boolean needConditionValue = (cst == NotAConstant) && (condCst == NotAConstant); + condition.generateOptimizedBoolean( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + needConditionValue); + + if (thenInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + thenInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, thenInitStateIndex); + } + // Then code generation + if (needTruePart) { + valueIfTrue.generateCode(currentScope, codeStream, valueRequired); + if (needFalsePart) { + // Jump over the else part + int position = codeStream.position; + codeStream.goto_(endifLabel); + codeStream.updateLastRecordedEndPC(position); + // Tune codestream stack size + if (valueRequired) { + codeStream.decrStackSize(returnTypeSlotSize); + } + } + } + if (needFalsePart) { + falseLabel.place(); + if (elseInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + elseInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, elseInitStateIndex); + } + valueIfFalse.generateCode(currentScope, codeStream, valueRequired); + // End of if statement + endifLabel.place(); + } + // May loose some local variable initializations : affecting the local variable attributes + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + } + // implicit conversion + if (valueRequired) + codeStream.generateImplicitConversion(implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + /** + * Optimized boolean code generation for the conditional operator ?: + */ + public void generateOptimizedBoolean( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean) // constant + || (valueIfTrue.implicitConversion >> 4) != T_boolean) { // non boolean values + super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); + return; + } + int pc = codeStream.position; + Constant cst = condition.constant; + Constant condCst = condition.conditionalConstant(); + boolean needTruePart = + !(((cst != NotAConstant) && (cst.booleanValue() == false)) + || ((condCst != NotAConstant) && (condCst.booleanValue() == false))); + boolean needFalsePart = + !(((cst != NotAConstant) && (cst.booleanValue() == true)) + || ((condCst != NotAConstant) && (condCst.booleanValue() == true))); + + Label internalFalseLabel, endifLabel = new Label(codeStream); + + // Generate code for the condition + boolean needConditionValue = (cst == NotAConstant) && (condCst == NotAConstant); + condition.generateOptimizedBoolean( + currentScope, + codeStream, + null, + internalFalseLabel = new Label(codeStream), + needConditionValue); + + if (thenInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + thenInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, thenInitStateIndex); + } + // Then code generation + if (needTruePart) { + valueIfTrue.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); + + if (needFalsePart) { + // Jump over the else part + int position = codeStream.position; + codeStream.goto_(endifLabel); + codeStream.updateLastRecordedEndPC(position); + // Tune codestream stack size + //if (valueRequired) { + // codeStream.decrStackSize(returnTypeSlotSize); + //} + } + } + if (needFalsePart) { + internalFalseLabel.place(); + if (elseInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + elseInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, elseInitStateIndex); + } + valueIfFalse.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); + + // End of if statement + endifLabel.place(); + } + // May loose some local variable initializations : affecting the local variable attributes + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + } + // no implicit conversion for boolean values + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public TypeBinding resolveType(BlockScope scope) { + // specs p.368 + constant = NotAConstant; + TypeBinding conditionType = condition.resolveTypeExpecting(scope, BooleanBinding); + TypeBinding valueIfTrueType = valueIfTrue.resolveType(scope); + TypeBinding valueIfFalseType = valueIfFalse.resolveType(scope); + if (conditionType == null || valueIfTrueType == null || valueIfFalseType == null) + return null; + + // Propagate the constant value from the valueIfTrue and valueIFFalse expression if it is possible + if (condition.constant != NotAConstant + && valueIfTrue.constant != NotAConstant + && valueIfFalse.constant != NotAConstant) { + // all terms are constant expression so we can propagate the constant + // from valueIFTrue or valueIfFalse to teh receiver constant + constant = + (condition.constant.booleanValue()) + ? valueIfTrue.constant + : valueIfFalse.constant; + } + if (valueIfTrueType == valueIfFalseType) { // harmed the implicit conversion + valueIfTrue.implicitWidening(valueIfTrueType, valueIfTrueType); + valueIfFalse.implicitConversion = valueIfTrue.implicitConversion; + if (valueIfTrueType == LongBinding || valueIfTrueType == DoubleBinding) { + returnTypeSlotSize = 2; + } + this.typeBinding = valueIfTrueType; + return valueIfTrueType; + } + // Determine the return type depending on argument types + // Numeric types + if (valueIfTrueType.isNumericType() && valueIfFalseType.isNumericType()) { + // (Short x Byte) or (Byte x Short)" + if ((valueIfTrueType == ByteBinding && valueIfFalseType == ShortBinding) + || (valueIfTrueType == ShortBinding && valueIfFalseType == ByteBinding)) { + valueIfTrue.implicitWidening(ShortBinding, valueIfTrueType); + valueIfFalse.implicitWidening(ShortBinding, valueIfFalseType); + this.typeBinding = ShortBinding; + return ShortBinding; + } + // x constant(Int) ---> and reciprocally + if ((valueIfTrueType == ByteBinding || valueIfTrueType == ShortBinding || valueIfTrueType == CharBinding) + && (valueIfFalseType == IntBinding + && valueIfFalse.isConstantValueOfTypeAssignableToType(valueIfFalseType, valueIfTrueType))) { + valueIfTrue.implicitWidening(valueIfTrueType, valueIfTrueType); + valueIfFalse.implicitWidening(valueIfTrueType, valueIfFalseType); + this.typeBinding = valueIfTrueType; + return valueIfTrueType; + } + if ((valueIfFalseType == ByteBinding + || valueIfFalseType == ShortBinding + || valueIfFalseType == CharBinding) + && (valueIfTrueType == IntBinding + && valueIfTrue.isConstantValueOfTypeAssignableToType(valueIfTrueType, valueIfFalseType))) { + valueIfTrue.implicitWidening(valueIfFalseType, valueIfTrueType); + valueIfFalse.implicitWidening(valueIfFalseType, valueIfFalseType); + this.typeBinding = valueIfFalseType; + return valueIfFalseType; + } + // Manual binary numeric promotion + // int + if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_int) + && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_int)) { + valueIfTrue.implicitWidening(IntBinding, valueIfTrueType); + valueIfFalse.implicitWidening(IntBinding, valueIfFalseType); + this.typeBinding = IntBinding; + return IntBinding; + } + // long + if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_long) + && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_long)) { + valueIfTrue.implicitWidening(LongBinding, valueIfTrueType); + valueIfFalse.implicitWidening(LongBinding, valueIfFalseType); + returnTypeSlotSize = 2; + this.typeBinding = LongBinding; + return LongBinding; + } + // float + if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_float) + && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_float)) { + valueIfTrue.implicitWidening(FloatBinding, valueIfTrueType); + valueIfFalse.implicitWidening(FloatBinding, valueIfFalseType); + this.typeBinding = FloatBinding; + return FloatBinding; + } + // double + valueIfTrue.implicitWidening(DoubleBinding, valueIfTrueType); + valueIfFalse.implicitWidening(DoubleBinding, valueIfFalseType); + returnTypeSlotSize = 2; + this.typeBinding = DoubleBinding; + return DoubleBinding; + } + // Type references (null null is already tested) + if ((valueIfTrueType.isBaseType() && valueIfTrueType != NullBinding) + || (valueIfFalseType.isBaseType() && valueIfFalseType != NullBinding)) { + scope.problemReporter().conditionalArgumentsIncompatibleTypes( + this, + valueIfTrueType, + valueIfFalseType); + return null; + } + if (scope.areTypesCompatible(valueIfFalseType, valueIfTrueType)) { + valueIfTrue.implicitWidening(valueIfTrueType, valueIfTrueType); + valueIfFalse.implicitWidening(valueIfTrueType, valueIfFalseType); + this.typeBinding = valueIfTrueType; + return valueIfTrueType; + } + if (scope.areTypesCompatible(valueIfTrueType, valueIfFalseType)) { + valueIfTrue.implicitWidening(valueIfFalseType, valueIfTrueType); + valueIfFalse.implicitWidening(valueIfFalseType, valueIfFalseType); + this.typeBinding = valueIfFalseType; + return valueIfFalseType; + } + scope.problemReporter().conditionalArgumentsIncompatibleTypes( + this, + valueIfTrueType, + valueIfFalseType); + return null; + } + + public String toStringExpressionNoParenthesis() { + return condition.toStringExpression() + " ? " + //$NON-NLS-1$ + valueIfTrue.toStringExpression() + " : " + //$NON-NLS-1$ + valueIfFalse.toStringExpression(); + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + if (visitor.visit(this, scope)) { + condition.traverse(visitor, scope); + valueIfTrue.traverse(visitor, scope); + valueIfFalse.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ConstructorDeclaration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ConstructorDeclaration.java new file mode 100644 index 0000000..d6a9244 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ConstructorDeclaration.java @@ -0,0 +1,394 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import java.util.ArrayList; + +import net.sourceforge.phpdt.core.compiler.*; +import net.sourceforge.phpdt.internal.compiler.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.parser.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; +import net.sourceforge.phpdt.internal.compiler.util.*; + +public class ConstructorDeclaration extends AbstractMethodDeclaration { + + public ExplicitConstructorCall constructorCall; + public final static char[] ConstantPoolName = "".toCharArray(); //$NON-NLS-1$ + public boolean isDefaultConstructor = false; + + public int referenceCount = 0; + // count how many times this constructor is referenced from other local constructors + + public ConstructorDeclaration(CompilationResult compilationResult){ + super(compilationResult); + } + + public void analyseCode( + ClassScope classScope, + InitializationFlowContext initializerFlowContext, + FlowInfo flowInfo) { + + if (ignoreFurtherInvestigation) + return; + try { + ExceptionHandlingFlowContext constructorContext = + new ExceptionHandlingFlowContext( + initializerFlowContext.parent, + this, + binding.thrownExceptions, + scope, + FlowInfo.DeadEnd); + initializerFlowContext.checkInitializerExceptions( + scope, + constructorContext, + flowInfo); + + // anonymous constructor can gain extra thrown exceptions from unhandled ones + if (binding.declaringClass.isAnonymousType()) { + ArrayList computedExceptions = constructorContext.extendedExceptions; + if (computedExceptions != null){ + int size; + if ((size = computedExceptions.size()) > 0){ + ReferenceBinding[] actuallyThrownExceptions; + computedExceptions.toArray(actuallyThrownExceptions = new ReferenceBinding[size]); + binding.thrownExceptions = actuallyThrownExceptions; + } + } + } + + // propagate to constructor call + if (constructorCall != null) { + // if calling 'this(...)', then flag all non-static fields as definitely + // set since they are supposed to be set inside other local constructor + if (constructorCall.accessMode == ExplicitConstructorCall.This) { + FieldBinding[] fields = binding.declaringClass.fields(); + for (int i = 0, count = fields.length; i < count; i++) { + FieldBinding field; + if (!(field = fields[i]).isStatic()) { + flowInfo.markAsDefinitelyAssigned(field); + } + } + } + flowInfo = constructorCall.analyseCode(scope, constructorContext, flowInfo); + } + // propagate to statements + if (statements != null) { + for (int i = 0, count = statements.length; i < count; i++) { + Statement stat; + if (!flowInfo.complainIfUnreachable((stat = statements[i]), scope)) { + flowInfo = stat.analyseCode(scope, constructorContext, flowInfo); + } + } + } + // check for missing returning path + needFreeReturn = + !((flowInfo == FlowInfo.DeadEnd) || flowInfo.isFakeReachable()); + + // check missing blank final field initializations + if ((constructorCall != null) + && (constructorCall.accessMode != ExplicitConstructorCall.This)) { + flowInfo = flowInfo.mergedWith(initializerFlowContext.initsOnReturn); + FieldBinding[] fields = binding.declaringClass.fields(); + for (int i = 0, count = fields.length; i < count; i++) { + FieldBinding field; + if ((!(field = fields[i]).isStatic()) + && field.isFinal() + && (!flowInfo.isDefinitelyAssigned(fields[i]))) { + scope.problemReporter().uninitializedBlankFinalField( + field, + isDefaultConstructor ? (AstNode) scope.referenceType() : this); + } + } + } + } catch (AbortMethod e) { + this.ignoreFurtherInvestigation = true; + } + } + + /** + * Bytecode generation for a constructor + * + * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope + * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile + */ + public void generateCode(ClassScope classScope, ClassFile classFile) { + int problemResetPC = 0; + if (ignoreFurtherInvestigation) { + if (this.binding == null) + return; // Handle methods with invalid signature or duplicates + int problemsLength; + IProblem[] problems = + scope.referenceCompilationUnit().compilationResult.getProblems(); + IProblem[] problemsCopy = new IProblem[problemsLength = problems.length]; + System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); + classFile.addProblemConstructor(this, binding, problemsCopy); + return; + } + try { + problemResetPC = classFile.contentsOffset; + this.internalGenerateCode(classScope, classFile); + } catch (AbortMethod e) { + if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) { + // a branch target required a goto_w, restart code gen in wide mode. + try { + if (statements != null) { + for (int i = 0, max = statements.length; i < max; i++) + statements[i].resetStateForCodeGeneration(); + } + classFile.contentsOffset = problemResetPC; + classFile.methodCount--; + classFile.codeStream.wideMode = true; // request wide mode + this.internalGenerateCode(classScope, classFile); // restart method generation + } catch (AbortMethod e2) { + int problemsLength; + IProblem[] problems = + scope.referenceCompilationUnit().compilationResult.getProblems(); + IProblem[] problemsCopy = new IProblem[problemsLength = problems.length]; + System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); + classFile.addProblemConstructor(this, binding, problemsCopy, problemResetPC); + } + } else { + int problemsLength; + IProblem[] problems = + scope.referenceCompilationUnit().compilationResult.getProblems(); + IProblem[] problemsCopy = new IProblem[problemsLength = problems.length]; + System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); + classFile.addProblemConstructor(this, binding, problemsCopy, problemResetPC); + } + } + } + + private void internalGenerateCode(ClassScope classScope, ClassFile classFile) { + classFile.generateMethodInfoHeader(binding); + int methodAttributeOffset = classFile.contentsOffset; + int attributeNumber = classFile.generateMethodInfoAttribute(binding); + if ((!binding.isNative()) && (!binding.isAbstract())) { + TypeDeclaration declaringType = classScope.referenceContext; + int codeAttributeOffset = classFile.contentsOffset; + classFile.generateCodeAttributeHeader(); + CodeStream codeStream = classFile.codeStream; + codeStream.reset(this, classFile); + // initialize local positions - including initializer scope. + ReferenceBinding declaringClass = binding.declaringClass; + int argSize = 0; + scope.computeLocalVariablePositions(// consider synthetic arguments if any + argSize = + declaringClass.isNestedType() + ? ((NestedTypeBinding) declaringClass).syntheticArgumentsOffset + : 1, + codeStream); + if (arguments != null) { + for (int i = 0, max = arguments.length; i < max; i++) { + // arguments initialization for local variable debug attributes + LocalVariableBinding argBinding; + codeStream.addVisibleLocalVariable(argBinding = arguments[i].binding); + argBinding.recordInitializationStartPC(0); + TypeBinding argType; + if ((argType = argBinding.type) == LongBinding || (argType == DoubleBinding)) { + argSize += 2; + } else { + argSize++; + } + } + } + MethodScope initializerScope = declaringType.initializerScope; + initializerScope.computeLocalVariablePositions(argSize, codeStream); + // offset by the argument size (since not linked to method scope) + + // generate constructor call + if (constructorCall != null) { + constructorCall.generateCode(scope, codeStream); + } + // generate field initialization - only if not invoking another constructor call of the same class + if ((constructorCall != null) + && (constructorCall.accessMode != ExplicitConstructorCall.This)) { + // generate synthetic fields initialization + if (declaringClass.isNestedType()) { + NestedTypeBinding nestedType = (NestedTypeBinding) declaringClass; + SyntheticArgumentBinding[] syntheticArgs = + nestedType.syntheticEnclosingInstances(); + for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length; + i < max; + i++) { + if (syntheticArgs[i].matchingField != null) { + codeStream.aload_0(); + codeStream.load(syntheticArgs[i]); + codeStream.putfield(syntheticArgs[i].matchingField); + } + } + syntheticArgs = nestedType.syntheticOuterLocalVariables(); + for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length; + i < max; + i++) { + if (syntheticArgs[i].matchingField != null) { + codeStream.aload_0(); + codeStream.load(syntheticArgs[i]); + codeStream.putfield(syntheticArgs[i].matchingField); + } + } + } + // generate user field initialization + if (declaringType.fields != null) { + for (int i = 0, max = declaringType.fields.length; i < max; i++) { + FieldDeclaration fieldDecl; + if (!(fieldDecl = declaringType.fields[i]).isStatic()) { + fieldDecl.generateCode(initializerScope, codeStream); + } + } + } + } + // generate statements + if (statements != null) { + for (int i = 0, max = statements.length; i < max; i++) { + statements[i].generateCode(scope, codeStream); + } + } + if (needFreeReturn) { + codeStream.return_(); + } + // local variable attributes + codeStream.exitUserScope(scope); + codeStream.recordPositionsFrom(0, this.bodyEnd); + classFile.completeCodeAttribute(codeAttributeOffset); + attributeNumber++; + } + classFile.completeMethodInfo(methodAttributeOffset, attributeNumber); + + // if a problem got reported during code gen, then trigger problem method creation + if (ignoreFurtherInvestigation) { + throw new AbortMethod(scope.referenceCompilationUnit().compilationResult); + } + } + + public boolean isConstructor() { + + return true; + } + + public boolean isDefaultConstructor() { + + return isDefaultConstructor; + } + + public boolean isInitializationMethod() { + + return true; + } + + public void parseStatements(Parser parser, CompilationUnitDeclaration unit) { + + //fill up the constructor body with its statements + if (ignoreFurtherInvestigation) + return; + if (isDefaultConstructor){ + constructorCall = + new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); + constructorCall.sourceStart = sourceStart; + constructorCall.sourceEnd = sourceEnd; + return; + } + parser.parse(this, unit); + + } + + /* + * Type checking for constructor, just another method, except for special check + * for recursive constructor invocations. + */ + public void resolveStatements(ClassScope upperScope) { +/* + // checking for recursive constructor call (protection) + if (!ignoreFurtherInvestigation && constructorCall == null){ + constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); + constructorCall.sourceStart = sourceStart; + constructorCall.sourceEnd = sourceEnd; + } +*/ + if (!CharOperation.equals(scope.enclosingSourceType().sourceName, selector)){ + scope.problemReporter().missingReturnType(this); + } + + // if null ==> an error has occurs at parsing time .... + if (constructorCall != null) { + // e.g. using super() in java.lang.Object + if (binding != null + && binding.declaringClass.id == T_Object + && constructorCall.accessMode != ExplicitConstructorCall.This) { + if (constructorCall.accessMode == ExplicitConstructorCall.Super) { + scope.problemReporter().cannotUseSuperInJavaLangObject(constructorCall); + } + constructorCall = null; + } else { + constructorCall.resolve(scope); + } + } + + super.resolveStatements(upperScope); + + // indirect reference: increment target constructor reference count + if (constructorCall != null){ + if (constructorCall.binding != null + && !constructorCall.isSuperAccess() + && constructorCall.binding.isValidBinding()) { + ((ConstructorDeclaration) + (upperScope.referenceContext.declarationOf(constructorCall.binding))).referenceCount++; + } + } + } + + public String toStringStatements(int tab) { + + String s = " {"; //$NON-NLS-1$ + if (constructorCall != null) { + s = s + "\n" + constructorCall.toString(tab) + ";"; //$NON-NLS-1$ //$NON-NLS-2$ + } + if (statements != null) { + for (int i = 0; i < statements.length; i++) { + s = s + "\n" + statements[i].toString(tab); //$NON-NLS-1$ + if (!(statements[i] instanceof Block)) { + s += ";"; //$NON-NLS-1$ + } + } + } + s += "\n" + tabString(tab == 0 ? 0 : tab - 1) + "}"; //$NON-NLS-1$ //$NON-NLS-2$ + //$NON-NLS-2$ //$NON-NLS-1$ + return s; + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + ClassScope classScope) { + + if (visitor.visit(this, classScope)) { + if (arguments != null) { + int argumentLength = arguments.length; + for (int i = 0; i < argumentLength; i++) + arguments[i].traverse(visitor, scope); + } + if (thrownExceptions != null) { + int thrownExceptionsLength = thrownExceptions.length; + for (int i = 0; i < thrownExceptionsLength; i++) + thrownExceptions[i].traverse(visitor, scope); + } + if (constructorCall != null) + constructorCall.traverse(visitor, scope); + if (statements != null) { + int statementsLength = statements.length; + for (int i = 0; i < statementsLength; i++) + statements[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, classScope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Continue.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Continue.java new file mode 100644 index 0000000..ceeaa7b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Continue.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class Continue extends BranchStatement { + + public Continue(char[] l, int s, int e) { + + super(l, s, e); + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // here requires to generate a sequence of finally blocks invocations depending corresponding + // to each of the traversed try statements, so that execution will terminate properly. + + // lookup the label, this should answer the returnContext + FlowContext targetContext; + if (label == null) { + targetContext = flowContext.getTargetContextForDefaultContinue(); + } else { + targetContext = flowContext.getTargetContextForContinueLabel(label); + } + if (targetContext == null) { + if (label == null) { + currentScope.problemReporter().invalidContinue(this); + } else { + currentScope.problemReporter().undefinedLabel(this); // need to improve + } + } else { + if (targetContext == FlowContext.NotContinuableContext) { + currentScope.problemReporter().invalidContinue(this); + return FlowInfo.DeadEnd; + } + targetLabel = targetContext.continueLabel(); + targetContext.recordContinueFrom(flowInfo); + FlowContext traversedContext = flowContext; + int subIndex = 0, maxSub = 5; + subroutines = new AstNode[maxSub]; + while (true) { + AstNode sub; + if ((sub = traversedContext.subRoutine()) != null) { + if (subIndex == maxSub) { + System.arraycopy( + subroutines, + 0, + (subroutines = new AstNode[maxSub *= 2]), + 0, + subIndex); + // grow + } + subroutines[subIndex++] = sub; + if (sub.cannotReturn()) { + break; + } + } + // remember the initialization at this + // point for dealing with blank final variables. + traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); + + if (traversedContext == targetContext) { + break; + } else { + traversedContext = traversedContext.parent; + } + } + // resize subroutines + if (subIndex != maxSub) { + System.arraycopy( + subroutines, + 0, + (subroutines = new AstNode[subIndex]), + 0, + subIndex); + } + } + return FlowInfo.DeadEnd; + } + + public String toString(int tab) { + + String s = tabString(tab); + s = s + "continue "; //$NON-NLS-1$ + if (label != null) + s = s + new String(label); + return s; + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + BlockScope blockScope) { + + visitor.visit(this, blockScope); + visitor.endVisit(this, blockScope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/DefaultCase.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/DefaultCase.java new file mode 100644 index 0000000..a27876d --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/DefaultCase.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class DefaultCase extends Statement { + + public CaseLabel targetLabel; + /** + * DefautCase constructor comment. + */ + public DefaultCase(int sourceEnd, int sourceStart) { + + this.sourceStart = sourceStart; + this.sourceEnd = sourceEnd; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + return flowInfo; + } + + /** + * Default case code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + targetLabel.place(); + codeStream.recordPositionsFrom(pc, this.sourceStart); + + } + public Constant resolveCase( + BlockScope scope, + TypeBinding testType, + SwitchStatement switchStatement) { + + // remember the default case into the associated switch statement + if (switchStatement.defaultCase != null) + scope.problemReporter().duplicateDefaultCase(this); + + // on error the last default will be the selected one .... (why not) .... + switchStatement.defaultCase = this; + resolve(scope); + return null; + } + + public String toString(int tab) { + + String s = tabString(tab); + s = s + "default : "; //$NON-NLS-1$ + return s; + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + BlockScope blockScope) { + + visitor.visit(this, blockScope); + visitor.endVisit(this, blockScope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/DoStatement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/DoStatement.java new file mode 100644 index 0000000..201e99c --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/DoStatement.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class DoStatement extends Statement { + + public Expression condition; + public Statement action; + + private Label breakLabel, continueLabel; + + // for local variables table attributes + int mergedInitStateIndex = -1; + + public DoStatement(Expression condition, Statement action, int s, int e) { + + this.sourceStart = s; + this.sourceEnd = e; + this.condition = condition; + this.action = action; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + breakLabel = new Label(); + continueLabel = new Label(); + LoopingFlowContext loopingContext = + new LoopingFlowContext( + flowContext, + this, + breakLabel, + continueLabel, + currentScope); + + Constant conditionConstant = condition.constant; + Constant conditionalConstant = condition.conditionalConstant(); + boolean isFalseCondition = + ((conditionConstant != NotAConstant) + && (conditionConstant.booleanValue() == false)) + || ((conditionalConstant != NotAConstant) + && (conditionalConstant.booleanValue() == false)); + + if ((action != null) && !action.isEmptyBlock()) { + flowInfo = action.analyseCode(currentScope, loopingContext, flowInfo.copy()); + + // code generation can be optimized when no need to continue in the loop + if ((flowInfo == FlowInfo.DeadEnd) || flowInfo.isFakeReachable()) { + if ((loopingContext.initsOnContinue == FlowInfo.DeadEnd) + || loopingContext.initsOnContinue.isFakeReachable()) { + continueLabel = null; + } else { + flowInfo = loopingContext.initsOnContinue; // for condition + if (isFalseCondition) { + // continueLabel = null; - cannot nil the label since may be targeted already by 'continue' statements + } else { + loopingContext.complainOnFinalAssignmentsInLoop(currentScope, flowInfo); + } + } + } else { + if (isFalseCondition) { + // continueLabel = null; - cannot nil the label since may be targeted already by 'continue' statements + } else { + loopingContext.complainOnFinalAssignmentsInLoop(currentScope, flowInfo); + } + } + } + LoopingFlowContext condLoopContext; + flowInfo = + condition.analyseCode( + currentScope, + (condLoopContext = + new LoopingFlowContext(flowContext, this, null, null, currentScope)), + (action == null + ? flowInfo + : (flowInfo.mergedWith(loopingContext.initsOnContinue)))); + condLoopContext.complainOnFinalAssignmentsInLoop(currentScope, flowInfo); + + // infinite loop + FlowInfo mergedInfo; + if ((condition.constant != NotAConstant) + && (condition.constant.booleanValue() == true)) { + mergedInfo = loopingContext.initsOnBreak; + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + + // end of loop: either condition false or break + mergedInfo = + flowInfo.initsWhenFalse().unconditionalInits().mergedWith( + loopingContext.initsOnBreak); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + + /** + * Do statement code generation + * + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + + // labels management + Label actionLabel = new Label(codeStream); + actionLabel.place(); + breakLabel.codeStream = codeStream; + if (continueLabel != null) { + continueLabel.codeStream = codeStream; + } + + // generate action + if (action != null) { + action.generateCode(currentScope, codeStream); + } + // generate condition + if (continueLabel != null) { + continueLabel.place(); + condition.generateOptimizedBoolean( + currentScope, + codeStream, + actionLabel, + null, + true); + } + breakLabel.place(); + + // May loose some local variable initializations : affecting the local variable attributes + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + + } + + public void resetStateForCodeGeneration() { + + this.breakLabel.resetStateForCodeGeneration(); + this.continueLabel.resetStateForCodeGeneration(); + } + + public void resolve(BlockScope scope) { + + TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding); + condition.implicitWidening(type, type); + if (action != null) + action.resolve(scope); + } + + public String toString(int tab) { + + String inFront, s = tabString(tab); + inFront = s; + s = s + "do"; //$NON-NLS-1$ + if (action == null) + s = s + " {}\n"; //$NON-NLS-1$ + else if (action instanceof Block) + s = s + "\n" + action.toString(tab + 1) + "\n"; //$NON-NLS-2$ //$NON-NLS-1$ + else + s = s + " {\n" + action.toString(tab + 1) + ";}\n"; //$NON-NLS-1$ //$NON-NLS-2$ + s = s + inFront + "while (" + condition.toStringExpression() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + return s; + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + if (action != null) { + action.traverse(visitor, scope); + } + condition.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/DoubleLiteral.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/DoubleLiteral.java new file mode 100644 index 0000000..3e7fba0 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/DoubleLiteral.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class DoubleLiteral extends NumberLiteral { + double value; +public DoubleLiteral(char[] token, int s, int e) { + super(token, s,e); +} +public void computeConstant() { + + //the source is correctly formated so the exception should never occurs + + Double computedValue; + try { computedValue = Double.valueOf(String.valueOf(source));} + catch(NumberFormatException e){return ;} //how can it happen ???? + + if (computedValue.doubleValue() > Double.MAX_VALUE) return ; //may be Infinity + if (computedValue.doubleValue() < Double.MIN_VALUE) + { //only a true 0 can be made of zeros :-) + //2.00000000000000000e-324 is illegal .... + label : + for (int i=0;i> 4) == T_double) + codeStream.generateInlinedValue(value); + else + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public TypeBinding literalType(BlockScope scope) { + return DoubleBinding; +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope blockScope) { + visitor.visit(this, blockScope); + visitor.endVisit(this, blockScope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/EmptyStatement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/EmptyStatement.java new file mode 100644 index 0000000..a4dd8e4 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/EmptyStatement.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream; +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; + +public class EmptyStatement extends Statement { + + public EmptyStatement(int startPosition, int endPosition) { + this.sourceStart = startPosition; + this.sourceEnd = endPosition; + } + + public void generateCode(BlockScope currentScope, CodeStream codeStream){ + // no bytecode, no need to check for reachability or recording source positions + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } + + public String toString(int tab) { + return tabString(tab) + ";"; //$NON-NLS-1$ + } +} + + diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/EqualExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/EqualExpression.java new file mode 100644 index 0000000..e2385de --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/EqualExpression.java @@ -0,0 +1,533 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class EqualExpression extends BinaryExpression { + +public EqualExpression(Expression left, Expression right,int operator) { + super(left,right,operator); +} +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) { + if ((left.constant != NotAConstant) && (left.constant.typeID() == T_boolean)) { + if (left.constant.booleanValue()) { // true == anything + // this is equivalent to the right argument inits + return right.analyseCode(currentScope, flowContext, flowInfo); + } else { // false == anything + // this is equivalent to the right argument inits negated + return right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition(); + } + } + if ((right.constant != NotAConstant) && (right.constant.typeID() == T_boolean)) { + if (right.constant.booleanValue()) { // anything == true + // this is equivalent to the right argument inits + return left.analyseCode(currentScope, flowContext, flowInfo); + } else { // anything == false + // this is equivalent to the right argument inits negated + return left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition(); + } + } + return right.analyseCode( + currentScope, flowContext, + left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).unconditionalInits(); + } else { //NOT_EQUAL : + if ((left.constant != NotAConstant) && (left.constant.typeID() == T_boolean)) { + if (!left.constant.booleanValue()) { // false != anything + // this is equivalent to the right argument inits + return right.analyseCode(currentScope, flowContext, flowInfo); + } else { // true != anything + // this is equivalent to the right argument inits negated + return right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition(); + } + } + if ((right.constant != NotAConstant) && (right.constant.typeID() == T_boolean)) { + if (!right.constant.booleanValue()) { // anything != false + // this is equivalent to the right argument inits + return left.analyseCode(currentScope, flowContext, flowInfo); + } else { // anything != true + // this is equivalent to the right argument inits negated + return left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition(); + } + } + return right.analyseCode( + currentScope, flowContext, + left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).asNegatedCondition().unconditionalInits(); + } +} +public final boolean areTypesCastCompatible(BlockScope scope, TypeBinding castTb, TypeBinding expressionTb) { + //see specifications p.68 + //A more complete version of this method is provided on + //CastExpression (it deals with constant and need runtime checkcast) + + + //========ARRAY=============== + if (expressionTb.isArrayType()) { + if (castTb.isArrayType()) { //------- (castTb.isArray) expressionTb.isArray ----------- + TypeBinding expressionEltTb = ((ArrayBinding) expressionTb).elementsType(scope); + if (expressionEltTb.isBaseType()) + // <---stop the recursion------- + return ((ArrayBinding) castTb).elementsType(scope) == expressionEltTb; + //recursivly on the elts... + return areTypesCastCompatible(scope, ((ArrayBinding) castTb).elementsType(scope), expressionEltTb); + } + if (castTb.isBaseType()) { + return false; + } + if (castTb.isClass()) { //------(castTb.isClass) expressionTb.isArray --------------- + if (scope.isJavaLangObject(castTb)) + return true; + return false; + } + if (castTb.isInterface()) { //------- (castTb.isInterface) expressionTb.isArray ----------- + if (scope.isJavaLangCloneable(castTb) || scope.isJavaIoSerializable(castTb)) { + return true; + } + return false; + } + + return false; + } + + //------------(castType) null-------------- + if (expressionTb == NullBinding) { + return !castTb.isBaseType(); + } + + //========BASETYPE============== + if (expressionTb.isBaseType()) { + return false; + } + + + //========REFERENCE TYPE=================== + + if (expressionTb.isClass()) { + if (castTb.isArrayType()) { // ---- (castTb.isArray) expressionTb.isClass ------- + if (scope.isJavaLangObject(expressionTb)) + return true; + } + if (castTb.isBaseType()) { + return false; + } + if (castTb.isClass()) { // ----- (castTb.isClass) expressionTb.isClass ------ + if (scope.areTypesCompatible(expressionTb, castTb)) + return true; + else { + if (scope.areTypesCompatible(castTb, expressionTb)) { + return true; + } + return false; + } + } + if (castTb.isInterface()) { // ----- (castTb.isInterface) expressionTb.isClass ------- + if (((ReferenceBinding) expressionTb).isFinal()) { //no subclass for expressionTb, thus compile-time check is valid + if (scope.areTypesCompatible(expressionTb, castTb)) + return true; + return false; + } else { + return true; + } + } + + return false; + } + if (expressionTb.isInterface()) { + if (castTb.isArrayType()) { // ----- (castTb.isArray) expressionTb.isInterface ------ + if (scope.isJavaLangCloneable(expressionTb) || scope.isJavaIoSerializable(expressionTb)) + //potential runtime error + { + return true; + } + return false; + } + if (castTb.isBaseType()) { + return false; + } + if (castTb.isClass()) { // ----- (castTb.isClass) expressionTb.isInterface -------- + if (scope.isJavaLangObject(castTb)) + return true; + if (((ReferenceBinding) castTb).isFinal()) { //no subclass for castTb, thus compile-time check is valid + if (scope.areTypesCompatible(castTb, expressionTb)) { + return true; + } + return false; + } + return true; + } + if (castTb.isInterface()) { // ----- (castTb.isInterface) expressionTb.isInterface ------- + if (castTb != expressionTb && (Scope.compareTypes(castTb, expressionTb) == NotRelated)) { + MethodBinding[] castTbMethods = ((ReferenceBinding) castTb).methods(); + int castTbMethodsLength = castTbMethods.length; + MethodBinding[] expressionTbMethods = ((ReferenceBinding) expressionTb).methods(); + int expressionTbMethodsLength = expressionTbMethods.length; + for (int i = 0; i < castTbMethodsLength; i++) { + for (int j = 0; j < expressionTbMethodsLength; j++) { + if (castTbMethods[i].selector == expressionTbMethods[j].selector) { + if (castTbMethods[i].returnType != expressionTbMethods[j].returnType) { + if (castTbMethods[i].areParametersEqual(expressionTbMethods[j])) { + return false; + } + } + } + } + } + } + return true; + } + + return false; + } + + return false; +} +public final void computeConstant(TypeBinding leftTb, TypeBinding rightTb) { + if ((left.constant != NotAConstant) && (right.constant != NotAConstant)) { + constant = + Constant.computeConstantOperationEQUAL_EQUAL( + left.constant, + leftTb.id, + EQUAL_EQUAL, + right.constant, + rightTb.id); + if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT_EQUAL) + constant = Constant.fromValue(!constant.booleanValue()); + } else { + constant = NotAConstant; + } +} +/** + * Normal == or != code generation. + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + + if (constant != NotAConstant) { + int pc = codeStream.position; + if (valueRequired) + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + Label falseLabel; + generateOptimizedBoolean( + currentScope, + codeStream, + null, + falseLabel = new Label(codeStream), + valueRequired); + if (falseLabel.hasForwardReferences()) { + if (valueRequired){ + // comparison is TRUE + codeStream.iconst_1(); + if ((bits & ValueForReturnMASK) != 0){ + codeStream.ireturn(); + // comparison is FALSE + falseLabel.place(); + codeStream.iconst_0(); + } else { + Label endLabel = new Label(codeStream); + codeStream.goto_(endLabel); + codeStream.decrStackSize(1); + // comparison is FALSE + falseLabel.place(); + codeStream.iconst_0(); + endLabel.place(); + } + } else { + falseLabel.place(); + } + } +} +/** + * Boolean operator code generation + * Optimized operations are: == and != + */ +public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) { + if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) { + super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); + return; + } + int pc = codeStream.position; + if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) { + if ((left.implicitConversion & 0xF) /*compile-time*/ == T_boolean) { + generateOptimizedBooleanEqual(currentScope, codeStream, trueLabel, falseLabel, valueRequired); + } else { + generateOptimizedNonBooleanEqual(currentScope, codeStream, trueLabel, falseLabel, valueRequired); + } + } else { + if ((left.implicitConversion & 0xF) /*compile-time*/ == T_boolean) { + generateOptimizedBooleanEqual(currentScope, codeStream, falseLabel, trueLabel, valueRequired); + } else { + generateOptimizedNonBooleanEqual(currentScope, codeStream, falseLabel, trueLabel, valueRequired); + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +/** + * Boolean generation for == with boolean operands + * + * Note this code does not optimize conditional constants !!!! + */ +public void generateOptimizedBooleanEqual(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) { + int pc = codeStream.position; + // optimized cases: true == x, false == x + if (left.constant != NotAConstant) { + boolean inline = left.constant.booleanValue(); + right.generateOptimizedBoolean(currentScope, codeStream, (inline ? trueLabel : falseLabel), (inline ? falseLabel : trueLabel), valueRequired); + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } // optimized cases: x == true, x == false + if (right.constant != NotAConstant) { + boolean inline = right.constant.booleanValue(); + left.generateOptimizedBoolean(currentScope, codeStream, (inline ? trueLabel : falseLabel), (inline ? falseLabel : trueLabel), valueRequired); + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + // default case + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + codeStream.if_icmpeq(trueLabel); + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.if_icmpne(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +/** + * Boolean generation for == with non-boolean operands + * + */ +public void generateOptimizedNonBooleanEqual(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) { + int pc = codeStream.position; + Constant inline; + if ((inline = right.constant) != NotAConstant) { + // optimized case: x == null + if (right.constant == NullConstant.Default) { + left.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + codeStream.ifnull(trueLabel); + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.ifnonnull(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + // optimized case: x == 0 + if (((left.implicitConversion >> 4) == T_int) && (inline.intValue() == 0)) { + left.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + codeStream.ifeq(trueLabel); + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.ifne(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + } + if ((inline = left.constant) != NotAConstant) { + // optimized case: null == x + if (left.constant == NullConstant.Default) { + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + codeStream.ifnull(trueLabel); + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.ifnonnull(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + // optimized case: 0 == x + if (((left.implicitConversion >> 4) == T_int) + && (inline.intValue() == 0)) { + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + codeStream.ifeq(trueLabel); + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.ifne(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + } + // default case + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + switch (left.implicitConversion >> 4) { // operand runtime type + case T_int : + codeStream.if_icmpeq(trueLabel); + break; + case T_float : + codeStream.fcmpl(); + codeStream.ifeq(trueLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.ifeq(trueLabel); + break; + case T_double : + codeStream.dcmpl(); + codeStream.ifeq(trueLabel); + break; + default : + codeStream.if_acmpeq(trueLabel); + } + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + switch (left.implicitConversion >> 4) { // operand runtime type + case T_int : + codeStream.if_icmpne(falseLabel); + break; + case T_float : + codeStream.fcmpl(); + codeStream.ifne(falseLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.ifne(falseLabel); + break; + case T_double : + codeStream.dcmpl(); + codeStream.ifne(falseLabel); + break; + default : + codeStream.if_acmpne(falseLabel); + } + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public boolean isCompactableOperation() { + return false; +} +public TypeBinding resolveType(BlockScope scope) { + // always return BooleanBinding + TypeBinding leftTb = left.resolveType(scope); + TypeBinding rightTb = right.resolveType(scope); + if (leftTb == null || rightTb == null){ + constant = NotAConstant; + return null; + } + + // both base type + if (leftTb.isBaseType() && rightTb.isBaseType()) { + // the code is an int + // (cast) left == (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 <<0 + int result = ResolveTypeTables[EQUAL_EQUAL][ (leftTb.id << 4) + rightTb.id]; + left.implicitConversion = result >>> 12; + right.implicitConversion = (result >>> 4) & 0x000FF; + bits |= result & 0xF; + if ((result & 0x0000F) == T_undefined) { + constant = Constant.NotAConstant; + scope.problemReporter().invalidOperator(this, leftTb, rightTb); + return null; + } + computeConstant(leftTb, rightTb); + this.typeBinding = BooleanBinding; + return BooleanBinding; + } + + // Object references + // spec 15.20.3 + if (areTypesCastCompatible(scope, rightTb, leftTb) || areTypesCastCompatible(scope, leftTb, rightTb)) { + // (special case for String) + if ((rightTb.id == T_String) && (leftTb.id == T_String)) + computeConstant(leftTb, rightTb); + else + constant = NotAConstant; + if (rightTb.id == T_String) + right.implicitConversion = String2String; + if (leftTb.id == T_String) + left.implicitConversion = String2String; + this.typeBinding = BooleanBinding; + return BooleanBinding; + } + constant = NotAConstant; + scope.problemReporter().notCompatibleTypesError(this, leftTb, rightTb); + return null; +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + if (visitor.visit(this, scope)) { + left.traverse(visitor, scope); + right.traverse(visitor, scope); + } + visitor.endVisit(this, scope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ExplicitConstructorCall.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ExplicitConstructorCall.java new file mode 100644 index 0000000..deeceb9 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ExplicitConstructorCall.java @@ -0,0 +1,316 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class ExplicitConstructorCall + extends Statement + implements InvocationSite { + + public Expression[] arguments; + public Expression qualification; + public MethodBinding binding; + + public int accessMode; + + public final static int ImplicitSuper = 1; + public final static int Super = 2; + public final static int This = 3; + + public VariableBinding[][] implicitArguments; + boolean discardEnclosingInstance; + + MethodBinding syntheticAccessor; + + public ExplicitConstructorCall(int accessMode) { + this.accessMode = accessMode; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // must verify that exceptions potentially thrown by this expression are caught in the method. + + try { + ((MethodScope) currentScope).isConstructorCall = true; + + // process enclosing instance + if (qualification != null) { + flowInfo = + qualification + .analyseCode(currentScope, flowContext, flowInfo) + .unconditionalInits(); + } + // process arguments + if (arguments != null) { + for (int i = 0, max = arguments.length; i < max; i++) { + flowInfo = + arguments[i] + .analyseCode(currentScope, flowContext, flowInfo) + .unconditionalInits(); + } + } + + ReferenceBinding[] thrownExceptions; + if ((thrownExceptions = binding.thrownExceptions) != NoExceptions) { + // check exceptions + flowContext.checkExceptionHandlers( + thrownExceptions, + (accessMode == ImplicitSuper) + ? (AstNode) currentScope.methodScope().referenceContext + : (AstNode) this, + flowInfo, + currentScope); + } + manageEnclosingInstanceAccessIfNecessary(currentScope); + manageSyntheticAccessIfNecessary(currentScope); + return flowInfo; + } finally { + ((MethodScope) currentScope).isConstructorCall = false; + } + } + + /** + * Constructor call code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + try { + ((MethodScope) currentScope).isConstructorCall = true; + + int pc = codeStream.position; + codeStream.aload_0(); + + // handling innerclass constructor invocation + ReferenceBinding targetType; + if ((targetType = binding.declaringClass).isNestedType()) { + codeStream.generateSyntheticArgumentValues( + currentScope, + targetType, + discardEnclosingInstance ? null : qualification, + this); + } + // regular code gen + if (arguments != null) { + for (int i = 0, max = arguments.length; i < max; i++) { + arguments[i].generateCode(currentScope, codeStream, true); + } + } + if (syntheticAccessor != null) { + // synthetic accessor got some extra arguments appended to its signature, which need values + for (int i = 0, + max = syntheticAccessor.parameters.length - binding.parameters.length; + i < max; + i++) { + codeStream.aconst_null(); + } + codeStream.invokespecial(syntheticAccessor); + } else { + codeStream.invokespecial(binding); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } finally { + ((MethodScope) currentScope).isConstructorCall = false; + } + } + + public boolean isImplicitSuper() { + //return true if I'm of these compiler added statement super(); + + return (accessMode == ImplicitSuper); + } + + public boolean isSuperAccess() { + + return accessMode != This; + } + + public boolean isTypeAccess() { + + return true; + } + + /* Inner emulation consists in either recording a dependency + * link only, or performing one level of propagation. + * + * Dependency mechanism is used whenever dealing with source target + * types, since by the time we reach them, we might not yet know their + * exact need. + */ + void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) { + ReferenceBinding superType; + + // perform some emulation work in case there is some and we are inside a local type only + if ((superType = binding.declaringClass).isNestedType() + && currentScope.enclosingSourceType().isLocalType()) { + + if (superType.isLocalType()) { + ((LocalTypeBinding) superType).addInnerEmulationDependent( + currentScope, + qualification != null, + true); + // request direct access + } else { + // locally propagate, since we already now the desired shape for sure + currentScope.propagateInnerEmulation(superType, qualification != null, true); + // request direct access + + } + } + } + + public void manageSyntheticAccessIfNecessary(BlockScope currentScope) { + + // perform some emulation work in case there is some and we are inside a local type only + if (binding.isPrivate() && (accessMode != This)) { + + if (currentScope + .environment() + .options + .isPrivateConstructorAccessChangingVisibility) { + binding.tagForClearingPrivateModifier(); + // constructor will not be dumped as private, no emulation required thus + } else { + syntheticAccessor = + ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding); + currentScope.problemReporter().needToEmulateMethodAccess(binding, this); + } + } + } + + public void resolve(BlockScope scope) { + // the return type should be void for a constructor. + // the test is made into getConstructor + + // mark the fact that we are in a constructor call..... + // unmark at all returns + try { + ((MethodScope) scope).isConstructorCall = true; + ReferenceBinding receiverType = scope.enclosingSourceType(); + if (accessMode != This) + receiverType = receiverType.superclass(); + + if (receiverType == null) { + return; + } + + // qualification should be from the type of the enclosingType + if (qualification != null) { + if (accessMode != Super) { + scope.problemReporter().unnecessaryEnclosingInstanceSpecification( + qualification, + receiverType); + } + ReferenceBinding enclosingType = receiverType.enclosingType(); + if (enclosingType == null) { + scope.problemReporter().unnecessaryEnclosingInstanceSpecification( + qualification, + receiverType); + discardEnclosingInstance = true; + } else { + TypeBinding qTb = qualification.resolveTypeExpecting(scope, enclosingType); + qualification.implicitWidening(qTb, qTb); + } + } + + // arguments buffering for the method lookup + TypeBinding[] argTypes = NoParameters; + if (arguments != null) { + boolean argHasError = false; // typeChecks all arguments + int length = arguments.length; + argTypes = new TypeBinding[length]; + for (int i = 0; i < length; i++) + if ((argTypes[i] = arguments[i].resolveType(scope)) == null) + argHasError = true; + if (argHasError) + return; + } + if ((binding = scope.getConstructor(receiverType, argTypes, this)) + .isValidBinding()) { + if (isMethodUseDeprecated(binding, scope)) + scope.problemReporter().deprecatedMethod(binding, this); + + // see for user-implicit widening conversion + if (arguments != null) { + int length = arguments.length; + TypeBinding[] paramTypes = binding.parameters; + for (int i = 0; i < length; i++) + arguments[i].implicitWidening(paramTypes[i], argTypes[i]); + } + } else { + if (binding.declaringClass == null) + binding.declaringClass = receiverType; + scope.problemReporter().invalidConstructor(this, binding); + } + } finally { + ((MethodScope) scope).isConstructorCall = false; + } + } + + public void setActualReceiverType(ReferenceBinding receiverType) { + // ignored + } + + public void setDepth(int depth) { + // ignore for here + } + + public void setFieldIndex(int depth) { + // ignore for here + } + + public String toString(int tab) { + + String s = tabString(tab); + if (qualification != null) + s = s + qualification.toStringExpression() + "."; //$NON-NLS-1$ + if (accessMode == This) { + s = s + "this("; //$NON-NLS-1$ + } else { + s = s + "super("; //$NON-NLS-1$ + } + if (arguments != null) + for (int i = 0; i < arguments.length; i++) { + s = s + arguments[i].toStringExpression(); + if (i != arguments.length - 1) + s = s + ", "; //$NON-NLS-1$ + } + s = s + ")"; //$NON-NLS-1$ + return s; + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + if (qualification != null) { + qualification.traverse(visitor, scope); + } + if (arguments != null) { + int argumentLength = arguments.length; + for (int i = 0; i < argumentLength; i++) + arguments[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Expression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Expression.java new file mode 100644 index 0000000..15ba5e3 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Expression.java @@ -0,0 +1,484 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; +import net.sourceforge.phpdt.internal.compiler.util.Util; + +public abstract class Expression extends Statement { + + //some expression may not be used - from a java semantic point + //of view only - as statements. Other may. In order to avoid the creation + //of wrappers around expression in order to tune them as expression + //Expression is a subclass of Statement. See the message isValidJavaStatement() + + public int implicitConversion; + + public Constant constant; + + public Expression() { + super(); + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo, + boolean valueRequired) { + + return analyseCode(currentScope, flowContext, flowInfo); + } + + public Constant conditionalConstant() { + + return constant; + } + + public static final boolean isConstantValueRepresentable( + Constant constant, + int constantTypeID, + int targetTypeID) { + + //true if there is no loss of precision while casting. + // constantTypeID == constant.typeID + if (targetTypeID == constantTypeID) + return true; + switch (targetTypeID) { + case T_char : + switch (constantTypeID) { + case T_char : + return true; + case T_double : + return constant.doubleValue() == constant.charValue(); + case T_float : + return constant.floatValue() == constant.charValue(); + case T_int : + return constant.intValue() == constant.charValue(); + case T_short : + return constant.shortValue() == constant.charValue(); + case T_byte : + return constant.byteValue() == constant.charValue(); + case T_long : + return constant.longValue() == constant.charValue(); + default : + return false;//boolean + } + + case T_float : + switch (constantTypeID) { + case T_char : + return constant.charValue() == constant.floatValue(); + case T_double : + return constant.doubleValue() == constant.floatValue(); + case T_float : + return true; + case T_int : + return constant.intValue() == constant.floatValue(); + case T_short : + return constant.shortValue() == constant.floatValue(); + case T_byte : + return constant.byteValue() == constant.floatValue(); + case T_long : + return constant.longValue() == constant.floatValue(); + default : + return false;//boolean + } + + case T_double : + switch (constantTypeID) { + case T_char : + return constant.charValue() == constant.doubleValue(); + case T_double : + return true; + case T_float : + return constant.floatValue() == constant.doubleValue(); + case T_int : + return constant.intValue() == constant.doubleValue(); + case T_short : + return constant.shortValue() == constant.doubleValue(); + case T_byte : + return constant.byteValue() == constant.doubleValue(); + case T_long : + return constant.longValue() == constant.doubleValue(); + default : + return false; //boolean + } + + case T_byte : + switch (constantTypeID) { + case T_char : + return constant.charValue() == constant.byteValue(); + case T_double : + return constant.doubleValue() == constant.byteValue(); + case T_float : + return constant.floatValue() == constant.byteValue(); + case T_int : + return constant.intValue() == constant.byteValue(); + case T_short : + return constant.shortValue() == constant.byteValue(); + case T_byte : + return true; + case T_long : + return constant.longValue() == constant.byteValue(); + default : + return false; //boolean + } + + case T_short : + switch (constantTypeID) { + case T_char : + return constant.charValue() == constant.shortValue(); + case T_double : + return constant.doubleValue() == constant.shortValue(); + case T_float : + return constant.floatValue() == constant.shortValue(); + case T_int : + return constant.intValue() == constant.shortValue(); + case T_short : + return true; + case T_byte : + return constant.byteValue() == constant.shortValue(); + case T_long : + return constant.longValue() == constant.shortValue(); + default : + return false; //boolean + } + + case T_int : + switch (constantTypeID) { + case T_char : + return constant.charValue() == constant.intValue(); + case T_double : + return constant.doubleValue() == constant.intValue(); + case T_float : + return constant.floatValue() == constant.intValue(); + case T_int : + return true; + case T_short : + return constant.shortValue() == constant.intValue(); + case T_byte : + return constant.byteValue() == constant.intValue(); + case T_long : + return constant.longValue() == constant.intValue(); + default : + return false; //boolean + } + + case T_long : + switch (constantTypeID) { + case T_char : + return constant.charValue() == constant.longValue(); + case T_double : + return constant.doubleValue() == constant.longValue(); + case T_float : + return constant.floatValue() == constant.longValue(); + case T_int : + return constant.intValue() == constant.longValue(); + case T_short : + return constant.shortValue() == constant.longValue(); + case T_byte : + return constant.byteValue() == constant.longValue(); + case T_long : + return true; + default : + return false; //boolean + } + + default : + return false; //boolean + } + } + + /** + * Expression statements are plain expressions, however they generate like + * normal expressions with no value required. + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + generateCode(currentScope, codeStream, false); + } + + /** + * Every expression is responsible for generating its implicit conversion when necessary. + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + if (constant != NotAConstant) { + // generate a constant expression + int pc = codeStream.position; + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } else { + // actual non-constant code generation + throw new ShouldNotImplement(Util.bind("ast.missingCode")); //$NON-NLS-1$ + } + } + + /** + * Default generation of a boolean value + */ + public void generateOptimizedBoolean( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + // a label valued to nil means: by default we fall through the case... + // both nil means we leave the value on the stack + + if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) { + int pc = codeStream.position; + if (constant.booleanValue() == true) { + // constant == true + if (valueRequired) { + if (falseLabel == null) { + // implicit falling through the FALSE case + if (trueLabel != null) { + codeStream.goto_(trueLabel); + } + } + } + } else { + if (valueRequired) { + if (falseLabel != null) { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.goto_(falseLabel); + } + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + generateCode(currentScope, codeStream, valueRequired); + // branching + int position = codeStream.position; + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // Implicit falling through the FALSE case + codeStream.ifne(trueLabel); + } + } else { + if (trueLabel == null) { + // Implicit falling through the TRUE case + codeStream.ifeq(falseLabel); + } else { + // No implicit fall through TRUE/FALSE --> should never occur + } + } + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(position); + } + + /* Optimized (java) code generation for string concatenations that involve StringBuffer + * creation: going through this path means that there is no need for a new StringBuffer + * creation, further operands should rather be only appended to the current one. + * By default: no optimization. + */ + public void generateOptimizedStringBuffer( + BlockScope blockScope, + net.sourceforge.phpdt.internal.compiler.codegen.CodeStream codeStream, + int typeID) { + + generateCode(blockScope, codeStream, true); + codeStream.invokeStringBufferAppendForType(typeID); + } + + /* Optimized (java) code generation for string concatenations that involve StringBuffer + * creation: going through this path means that there is no need for a new StringBuffer + * creation, further operands should rather be only appended to the current one. + */ + public void generateOptimizedStringBufferCreation( + BlockScope blockScope, + CodeStream codeStream, + int typeID) { + + // Optimization only for integers and strings + if (typeID == T_Object) { + // in the case the runtime value of valueOf(Object) returns null, we have to use append(Object) instead of directly valueOf(Object) + // append(Object) returns append(valueOf(Object)), which means that the null case is handled by append(String). + codeStream.newStringBuffer(); + codeStream.dup(); + codeStream.invokeStringBufferDefaultConstructor(); + generateCode(blockScope, codeStream, true); + codeStream.invokeStringBufferAppendForType(T_Object); + return; + } + codeStream.newStringBuffer(); + codeStream.dup(); + if ((typeID == T_String) || (typeID == T_null)) { + if (constant != NotAConstant) { + codeStream.ldc(constant.stringValue()); + } else { + generateCode(blockScope, codeStream, true); + codeStream.invokeStringValueOf(T_Object); + } + } else { + generateCode(blockScope, codeStream, true); + codeStream.invokeStringValueOf(typeID); + } + codeStream.invokeStringBufferStringConstructor(); + } + + // Base types need that the widening is explicitly done by the compiler using some bytecode like i2f + public void implicitWidening( + TypeBinding runtimeTimeType, + TypeBinding compileTimeType) { + + if (runtimeTimeType == null || compileTimeType == null) + return; + + if (compileTimeType.id == T_null) { + // this case is possible only for constant null + // The type of runtime is a reference type + // The code gen use the constant id thus any value + // for the runtime id (akak the <<4) could be used. + // T_Object is used as some general T_reference + implicitConversion = (T_Object << 4) + T_null; + return; + } + + switch (runtimeTimeType.id) { + case T_byte : + case T_short : + case T_char : + implicitConversion = (T_int << 4) + compileTimeType.id; + break; + case T_String : + case T_float : + case T_boolean : + case T_double : + case T_int : //implicitConversion may result in i2i which will result in NO code gen + case T_long : + implicitConversion = (runtimeTimeType.id << 4) + compileTimeType.id; + break; + default : //nothing on regular object ref + } + } + + public boolean isCompactableOperation() { + + return false; + } + + //Return true if the conversion is done AUTOMATICALLY by the vm + //while the javaVM is an int based-machine, thus for example pushing + //a byte onto the stack , will automatically creates a int on the stack + //(this request some work d be done by the VM on signed numbers) + public boolean isConstantValueOfTypeAssignableToType( + TypeBinding constantType, + TypeBinding targetType) { + + if (constant == Constant.NotAConstant) + return false; + if (constantType == targetType) + return true; + if (constantType.isBaseType() && targetType.isBaseType()) { + //No free assignment conversion from anything but to integral ones. + if ((constantType == IntBinding + || BaseTypeBinding.isWidening(T_int, constantType.id)) + && (BaseTypeBinding.isNarrowing(targetType.id, T_int))) { + //use current explicit conversion in order to get some new value to compare with current one + return isConstantValueRepresentable(constant, constantType.id, targetType.id); + } + } + return false; + } + + public boolean isTypeReference() { + return false; + } + + public void resolve(BlockScope scope) { + // drops the returning expression's type whatever the type is. + + this.resolveType(scope); + return; + } + + public TypeBinding resolveType(BlockScope scope) { + // by default... subclasses should implement a better TC if required. + + return null; + } + + public TypeBinding resolveTypeExpecting( + BlockScope scope, + TypeBinding expectedTb) { + + TypeBinding thisTb = this.resolveType(scope); + if (thisTb == null) + return null; + if (!scope.areTypesCompatible(thisTb, expectedTb)) { + scope.problemReporter().typeMismatchError(thisTb, expectedTb, this); + return null; + } + return thisTb; + } + + public String toString(int tab) { + + //Subclass re-define toStringExpression + String s = tabString(tab); + if (constant != null) + //before TC has runned + if (constant != NotAConstant) + //after the TC has runned + s += " /*cst:" + constant.toString() + "*/ "; //$NON-NLS-1$ //$NON-NLS-2$ + return s + toStringExpression(tab); + } + + //Subclass re-define toStringExpression + //This method is abstract and should never be called + //but we provide some code that is running.....just in case + //of developpement time (while every thing is not built) + public String toStringExpression() { + + return super.toString(0); + } + + public String toStringExpression(int tab) { + // default is regular toString expression (qualified allocation expressions redifine this method) + return this.toStringExpression(); + } + + public Expression toTypeReference() { + //by default undefined + + //this method is meanly used by the parser in order to transform + //an expression that is used as a type reference in a cast .... + //--appreciate the fact that castExpression and ExpressionWithParenthesis + //--starts with the same pattern..... + + return this; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ExtendedStringLiteral.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ExtendedStringLiteral.java new file mode 100644 index 0000000..e4c0dd1 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ExtendedStringLiteral.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; + +public class ExtendedStringLiteral extends StringLiteral { + + private static final int INIT_SIZE = 30; + + /** + * Build a string+char literal + */ + public ExtendedStringLiteral(StringLiteral str, CharLiteral character) { + + super(str.source, str.sourceStart, str.sourceEnd); + extendWith(character); + } + + /** + * Build a two-strings literal + * */ + public ExtendedStringLiteral(StringLiteral str1, StringLiteral str2) { + + super(str1.source, str1.sourceStart, str1.sourceEnd); + extendWith(str2); + } + + /** + * Add the lit source to mine, just as if it was mine + */ + public ExtendedStringLiteral extendWith(CharLiteral lit) { + + //update the source + int length = source.length; + System.arraycopy(source, 0, (source = new char[length + 1]), 0, length); + source[length] = lit.value; + //position at the end of all literals + sourceEnd = lit.sourceEnd; + return this; + } + + /** + * Add the lit source to mine, just as if it was mine + */ + public ExtendedStringLiteral extendWith(StringLiteral lit) { + + //uddate the source + int length = source.length; + System.arraycopy( + source, + 0, + source = new char[length + lit.source.length], + 0, + length); + System.arraycopy(lit.source, 0, source, length, lit.source.length); + //position at the end of all literals + sourceEnd = lit.sourceEnd; + return this; + } + + public String toStringExpression() { + + String str = "ExtendedStringLiteral{" + new String(source) + "}"; //$NON-NLS-2$ //$NON-NLS-1$ + return str; + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/FalseLiteral.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/FalseLiteral.java new file mode 100644 index 0000000..ba6f7ad --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/FalseLiteral.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class FalseLiteral extends MagicLiteral { + static final char[] source = {'f', 'a', 'l', 's', 'e'}; +public FalseLiteral(int s , int e) { + super(s,e); +} +public void computeConstant() { + + constant = Constant.fromValue(false);} +/** + * Code generation for false literal + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + int pc = codeStream.position; + if (valueRequired) + codeStream.iconst_0(); + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) { + + // falseLabel being not nil means that we will not fall through into the FALSE case + + int pc = codeStream.position; + if (valueRequired) { + if (falseLabel != null) { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.goto_(falseLabel); + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public TypeBinding literalType(BlockScope scope) { + return BooleanBinding; +} +/** + * + */ +public char[] source() { + return source; +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/FieldDeclaration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/FieldDeclaration.java new file mode 100644 index 0000000..b1fa8d0 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/FieldDeclaration.java @@ -0,0 +1,214 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class FieldDeclaration extends AbstractVariableDeclaration { + public FieldBinding binding; + boolean hasBeenResolved = false; + + //allows to retrieve both the "type" part of the declaration (part1) + //and also the part that decribe the name and the init and optionally + //some other dimension ! .... + //public int[] a, b[] = X, c ; + //for b that would give for + // - part1 : public int[] + // - part2 : b[] = X, + + public int endPart1Position; + public int endPart2Position; + + public FieldDeclaration() { + } + + public FieldDeclaration( + Expression initialization, + char[] name, + int sourceStart, + int sourceEnd) { + + this.initialization = initialization; + this.name = name; + + //due to some declaration like + // int x, y = 3, z , x ; + //the sourceStart and the sourceEnd is ONLY on the name + this.sourceStart = sourceStart; + this.sourceEnd = sourceEnd; + } + + public FlowInfo analyseCode( + MethodScope initializationScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // cannot define static non-constant field inside nested class + if (binding != null + && binding.isValidBinding() + && binding.isStatic() + && binding.constant == NotAConstant + && binding.declaringClass.isNestedType() + && binding.declaringClass.isClass() + && !binding.declaringClass.isStatic()) { + initializationScope.problemReporter().unexpectedStaticModifierForField( + (SourceTypeBinding) binding.declaringClass, + this); + } + + if (initialization != null) { + flowInfo = + initialization + .analyseCode(initializationScope, flowContext, flowInfo) + .unconditionalInits(); + flowInfo.markAsDefinitelyAssigned(binding); + } else { + flowInfo.markAsDefinitelyNotAssigned(binding); + // clear the bit in case it was already set (from enclosing info) + } + return flowInfo; + } + + /** + * Code generation for a field declaration: + * i.e. normal assignment to a field + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + // do not generate initialization code if final and static (constant is then + // recorded inside the field itself). + int pc = codeStream.position; + boolean isStatic; + if (initialization != null + && !((isStatic = binding.isStatic()) && binding.constant != NotAConstant)) { + // non-static field, need receiver + if (!isStatic) + codeStream.aload_0(); + // generate initialization value + initialization.generateCode(currentScope, codeStream, true); + // store into field + if (isStatic) { + codeStream.putstatic(binding); + } else { + codeStream.putfield(binding); + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public TypeBinding getTypeBinding(Scope scope) { + + return type.getTypeBinding(scope); + } + + public boolean isField() { + + return true; + } + + public boolean isStatic() { + + if (binding != null) + return binding.isStatic(); + return (modifiers & AccStatic) != 0; + } + + public String name() { + + return String.valueOf(name); + } + + public void resolve(MethodScope initializationScope) { + + // the two could be regrouped into + // a single line but it is clearer to have two lines while the reason of their + // existence is not at all the same. See comment for the second one. + + //-------------------------------------------------------- + if (!this.hasBeenResolved && binding != null && this.binding.isValidBinding()) { + + this.hasBeenResolved = true; + + if (isTypeUseDeprecated(this.binding.type, initializationScope)) + initializationScope.problemReporter().deprecatedType(this.binding.type, this.type); + + this.type.binding = this.binding.type; // update binding for type reference + + // the resolution of the initialization hasn't been done + if (this.initialization == null) { + this.binding.constant = Constant.NotAConstant; + } else { + int previous = initializationScope.fieldDeclarationIndex; + try { + initializationScope.fieldDeclarationIndex = this.binding.id; + + // break dead-lock cycles by forcing constant to NotAConstant + this.binding.constant = Constant.NotAConstant; + + TypeBinding typeBinding = this.binding.type; + TypeBinding initializationTypeBinding; + + if (initialization instanceof ArrayInitializer) { + + if ((initializationTypeBinding = this.initialization.resolveTypeExpecting(initializationScope, typeBinding)) != null) { + ((ArrayInitializer) this.initialization).binding = (ArrayBinding) initializationTypeBinding; + this.initialization.implicitWidening(typeBinding, initializationTypeBinding); + } + } else if ((initializationTypeBinding = initialization.resolveType(initializationScope)) != null) { + + if (this.initialization.isConstantValueOfTypeAssignableToType(initializationTypeBinding, typeBinding) + || (typeBinding.isBaseType() && BaseTypeBinding.isWidening(typeBinding.id, initializationTypeBinding.id))) { + + this.initialization.implicitWidening(typeBinding, initializationTypeBinding); + + } else if (initializationScope.areTypesCompatible(initializationTypeBinding, typeBinding)) { + this.initialization.implicitWidening(typeBinding, initializationTypeBinding); + + } else { + initializationScope.problemReporter().typeMismatchError(initializationTypeBinding, typeBinding, this); + } + if (this.binding.isFinal()){ // cast from constant actual type to variable type + this.binding.constant = + this.initialization.constant.castTo( + (this.binding.type.id << 4) + this.initialization.constant.typeID()); + } + } else { + this.binding.constant = NotAConstant; + } + } finally { + initializationScope.fieldDeclarationIndex = previous; + if (this.binding.constant == null) + this.binding.constant = Constant.NotAConstant; + } + } + } + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, MethodScope scope) { + + if (visitor.visit(this, scope)) { + type.traverse(visitor, scope); + if (initialization != null) + initialization.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/FieldReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/FieldReference.java new file mode 100644 index 0000000..5cb69fd --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/FieldReference.java @@ -0,0 +1,568 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class FieldReference extends Reference implements InvocationSite { + + public Expression receiver; + public char[] token; + public FieldBinding binding, codegenBinding; + public long nameSourcePosition; //(start<<32)+end + MethodBinding syntheticReadAccessor, syntheticWriteAccessor; + public TypeBinding receiverType; + + public FieldReference(char[] source, long pos) { + + token = source; + nameSourcePosition = pos; + //by default the position are the one of the field (not true for super access) + sourceStart = (int) (pos >>> 32); + sourceEnd = (int) (pos & 0x00000000FFFFFFFFL); + bits |= BindingIds.FIELD; + + } + + public FlowInfo analyseAssignment( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo, + Assignment assignment, + boolean isCompound) { + + // compound assignment extra work + if (isCompound) { // check the variable part is initialized if blank final + if (binding.isFinal() + && receiver.isThis() + && currentScope.allowBlankFinalFieldAssignment(binding) + && (!flowInfo.isDefinitelyAssigned(binding))) { + currentScope.problemReporter().uninitializedBlankFinalField(binding, this); + // we could improve error msg here telling "cannot use compound assignment on final blank field" + } + manageSyntheticReadAccessIfNecessary(currentScope); + } + if (assignment.expression != null) { + flowInfo = + assignment + .expression + .analyseCode(currentScope, flowContext, flowInfo) + .unconditionalInits(); + } + flowInfo = + receiver + .analyseCode(currentScope, flowContext, flowInfo, !binding.isStatic()) + .unconditionalInits(); + manageSyntheticWriteAccessIfNecessary(currentScope); + + // check if assigning a final field + if (binding.isFinal()) { + // in a context where it can be assigned? + if (receiver.isThis() + && !(receiver instanceof QualifiedThisReference) + && currentScope.allowBlankFinalFieldAssignment(binding)) { + if (flowInfo.isPotentiallyAssigned(binding)) { + currentScope.problemReporter().duplicateInitializationOfBlankFinalField( + binding, + this); + } + flowInfo.markAsDefinitelyAssigned(binding); + flowContext.recordSettingFinal(binding, this); + } else { + // assigning a final field outside an initializer or constructor + currentScope.problemReporter().cannotAssignToFinalField(binding, this); + } + } + return flowInfo; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + return analyseCode(currentScope, flowContext, flowInfo, true); + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo, + boolean valueRequired) { + + receiver.analyseCode(currentScope, flowContext, flowInfo, !binding.isStatic()); + if (valueRequired) { + manageSyntheticReadAccessIfNecessary(currentScope); + } + return flowInfo; + } + + public FieldBinding fieldBinding() { + + return binding; + } + + public void generateAssignment( + BlockScope currentScope, + CodeStream codeStream, + Assignment assignment, + boolean valueRequired) { + + receiver.generateCode( + currentScope, + codeStream, + !this.codegenBinding.isStatic()); + assignment.expression.generateCode(currentScope, codeStream, true); + fieldStore( + codeStream, + this.codegenBinding, + syntheticWriteAccessor, + valueRequired); + if (valueRequired) { + codeStream.generateImplicitConversion(assignment.implicitConversion); + } + } + + /** + * Field reference code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + if (constant != NotAConstant) { + if (valueRequired) { + codeStream.generateConstant(constant, implicitConversion); + } + } else { + boolean isStatic = this.codegenBinding.isStatic(); + receiver.generateCode( + currentScope, + codeStream, + valueRequired && (!isStatic) && (this.codegenBinding.constant == NotAConstant)); + if (valueRequired) { + if (this.codegenBinding.constant == NotAConstant) { + if (this.codegenBinding.declaringClass == null) { // array length + codeStream.arraylength(); + } else { + if (syntheticReadAccessor == null) { + if (isStatic) { + codeStream.getstatic(this.codegenBinding); + } else { + codeStream.getfield(this.codegenBinding); + } + } else { + codeStream.invokestatic(syntheticReadAccessor); + } + } + codeStream.generateImplicitConversion(implicitConversion); + } else { + codeStream.generateConstant(this.codegenBinding.constant, implicitConversion); + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public void generateCompoundAssignment( + BlockScope currentScope, + CodeStream codeStream, + Expression expression, + int operator, + int assignmentImplicitConversion, + boolean valueRequired) { + + boolean isStatic; + receiver.generateCode( + currentScope, + codeStream, + !(isStatic = this.codegenBinding.isStatic())); + if (isStatic) { + if (syntheticReadAccessor == null) { + codeStream.getstatic(this.codegenBinding); + } else { + codeStream.invokestatic(syntheticReadAccessor); + } + } else { + codeStream.dup(); + if (syntheticReadAccessor == null) { + codeStream.getfield(this.codegenBinding); + } else { + codeStream.invokestatic(syntheticReadAccessor); + } + } + int operationTypeID; + if ((operationTypeID = implicitConversion >> 4) == T_String) { + codeStream.generateStringAppend(currentScope, null, expression); + } else { + // promote the array reference to the suitable operation type + codeStream.generateImplicitConversion(implicitConversion); + // generate the increment value (will by itself be promoted to the operation value) + if (expression == IntLiteral.One) { // prefix operation + codeStream.generateConstant(expression.constant, implicitConversion); + } else { + expression.generateCode(currentScope, codeStream, true); + } + // perform the operation + codeStream.sendOperator(operator, operationTypeID); + // cast the value back to the array reference type + codeStream.generateImplicitConversion(assignmentImplicitConversion); + } + fieldStore( + codeStream, + this.codegenBinding, + syntheticWriteAccessor, + valueRequired); + } + + public void generatePostIncrement( + BlockScope currentScope, + CodeStream codeStream, + CompoundAssignment postIncrement, + boolean valueRequired) { + + boolean isStatic; + receiver.generateCode( + currentScope, + codeStream, + !(isStatic = this.codegenBinding.isStatic())); + if (isStatic) { + if (syntheticReadAccessor == null) { + codeStream.getstatic(this.codegenBinding); + } else { + codeStream.invokestatic(syntheticReadAccessor); + } + } else { + codeStream.dup(); + if (syntheticReadAccessor == null) { + codeStream.getfield(this.codegenBinding); + } else { + codeStream.invokestatic(syntheticReadAccessor); + } + } + if (valueRequired) { + if (isStatic) { + if ((this.codegenBinding.type == LongBinding) + || (this.codegenBinding.type == DoubleBinding)) { + codeStream.dup2(); + } else { + codeStream.dup(); + } + } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value] + if ((this.codegenBinding.type == LongBinding) + || (this.codegenBinding.type == DoubleBinding)) { + codeStream.dup2_x1(); + } else { + codeStream.dup_x1(); + } + } + } + codeStream.generateConstant( + postIncrement.expression.constant, + implicitConversion); + codeStream.sendOperator(postIncrement.operator, this.codegenBinding.type.id); + codeStream.generateImplicitConversion( + postIncrement.assignmentImplicitConversion); + fieldStore(codeStream, this.codegenBinding, syntheticWriteAccessor, false); + } + + public static final Constant getConstantFor( + FieldBinding binding, + boolean implicitReceiver, + Reference reference, + Scope referenceScope, + int indexInQualification) { + + //propagation of the constant. + + //ref can be a FieldReference, a SingleNameReference or a QualifiedNameReference + //indexInQualification may have a value greater than zero only for QualifiednameReference + //if ref==null then indexInQualification==0 AND implicitReceiver == false. This case is a + //degenerated case where a fake reference field (null) + //is associted to a real FieldBinding in order + //to allow its constant computation using the regular path (i.e. find the fieldDeclaration + //and proceed to its type resolution). As implicitReceiver is false, no error reporting + //against ref will be used ==> no nullPointerException risk .... + + //special treatment for langage-built-in field (their declaring class is null) + if (binding.declaringClass == null) { + //currently only one field "length" : the constant computation is never done + return NotAConstant; + } + if (!binding.isFinal()) { + return binding.constant = NotAConstant; + } + if (binding.constant != null) { + if (indexInQualification == 0) { + return binding.constant; + } + //see previous comment for the (sould-always-be) valid cast + QualifiedNameReference qualifiedReference = (QualifiedNameReference) reference; + if (indexInQualification == (qualifiedReference.indexOfFirstFieldBinding - 1)) { + return binding.constant; + } + return NotAConstant; + } + + //The field has not been yet type checked. + //It also means that the field is not coming from a class that + //has already been compiled. It can only be from a class within + //compilation units to process. Thus the field is NOT from a BinaryTypeBinbing + + SourceTypeBinding typeBinding = (SourceTypeBinding) binding.declaringClass; + TypeDeclaration typeDecl = typeBinding.scope.referenceContext; + FieldDeclaration fieldDecl = typeDecl.declarationOf(binding); + + //what scope to use (depend on the staticness of the field binding) + MethodScope fieldScope = + binding.isStatic() + ? typeDecl.staticInitializerScope + : typeDecl.initializerScope; + + if (implicitReceiver) { //Determine if the ref is legal in the current class of the field + //i.e. not a forward reference .... (they are allowed when the receiver is explicit ! ... Please don't ask me why !...yet another java mystery...) + if (fieldScope.fieldDeclarationIndex == MethodScope.NotInFieldDecl) { + // no field is currently being analysed in typeDecl + fieldDecl.resolve(fieldScope); //side effect on binding :-) ... + return binding.constant; + } + //We are re-entering the same class fields analysing + if ((reference != null) + && (binding.declaringClass == referenceScope.enclosingSourceType()) // only complain for access inside same type + && (binding.id > fieldScope.fieldDeclarationIndex)) { + //forward reference. The declaration remains unresolved. + referenceScope.problemReporter().forwardReference(reference, indexInQualification, typeBinding); + return NotAConstant; + } + fieldDecl.resolve(fieldScope); //side effect on binding :-) ... + return binding.constant; + } + //the field reference is explicity. It has to be a "simple" like field reference to get the + //constant propagation. For example in Packahe.Type.field1.field2 , field1 may have its + //constant having a propagation where field2 is always not propagating its + if (indexInQualification == 0) { + fieldDecl.resolve(fieldScope); //side effect on binding :-) ... + return binding.constant; + } + // Side-effect on the field binding may not be propagated out for the qualified reference + // unless it occurs in first place of the name sequence + fieldDecl.resolve(fieldScope); //side effect on binding :-) ... + //see previous comment for the cast that should always be valid + QualifiedNameReference qualifiedReference = (QualifiedNameReference) reference; + if (indexInQualification == (qualifiedReference.indexOfFirstFieldBinding - 1)) { + return binding.constant; + } else { + return NotAConstant; + } + } + + public boolean isSuperAccess() { + + return receiver.isSuper(); + } + + public boolean isTypeAccess() { + + return receiver != null && receiver.isTypeReference(); + } + + /* + * No need to emulate access to protected fields since not implicitly accessed + */ + public void manageSyntheticReadAccessIfNecessary(BlockScope currentScope) { + + if (binding.isPrivate()) { + if ((currentScope.enclosingSourceType() != binding.declaringClass) + && (binding.constant == NotAConstant)) { + syntheticReadAccessor = + ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding, true); + currentScope.problemReporter().needToEmulateFieldReadAccess(binding, this); + return; + } + + } else if (receiver instanceof QualifiedSuperReference) { // qualified super + + // qualified super need emulation always + SourceTypeBinding destinationType = + (SourceTypeBinding) (((QualifiedSuperReference) receiver) + .currentCompatibleType); + syntheticReadAccessor = destinationType.addSyntheticMethod(binding, true); + currentScope.problemReporter().needToEmulateFieldReadAccess(binding, this); + return; + + } else if (binding.isProtected()) { + + SourceTypeBinding enclosingSourceType; + if (((bits & DepthMASK) != 0) + && binding.declaringClass.getPackage() + != (enclosingSourceType = currentScope.enclosingSourceType()).getPackage()) { + + SourceTypeBinding currentCompatibleType = + (SourceTypeBinding) enclosingSourceType.enclosingTypeAt( + (bits & DepthMASK) >> DepthSHIFT); + syntheticReadAccessor = currentCompatibleType.addSyntheticMethod(binding, true); + currentScope.problemReporter().needToEmulateFieldReadAccess(binding, this); + return; + } + } + // if the binding declaring class is not visible, need special action + // for runtime compatibility on 1.2 VMs : change the declaring class of the binding + // NOTE: from 1.4 on, field's declaring class is touched if any different from receiver type + if (binding.declaringClass != this.receiverType + && !this.receiverType.isArrayType() + && binding.declaringClass != null // array.length + && binding.constant == NotAConstant + && ((currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4 + && binding.declaringClass.id != T_Object) + //no change for Object fields (in case there was) + || !binding.declaringClass.canBeSeenBy(currentScope))) { + this.codegenBinding = + currentScope.enclosingSourceType().getUpdatedFieldBinding( + binding, + (ReferenceBinding) this.receiverType); + } + } + + /* + * No need to emulate access to protected fields since not implicitly accessed + */ + public void manageSyntheticWriteAccessIfNecessary(BlockScope currentScope) { + + if (binding.isPrivate()) { + if (currentScope.enclosingSourceType() != binding.declaringClass) { + syntheticWriteAccessor = + ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding, false); + currentScope.problemReporter().needToEmulateFieldWriteAccess(binding, this); + return; + } + + } else if (receiver instanceof QualifiedSuperReference) { // qualified super + + // qualified super need emulation always + SourceTypeBinding destinationType = + (SourceTypeBinding) (((QualifiedSuperReference) receiver) + .currentCompatibleType); + syntheticWriteAccessor = destinationType.addSyntheticMethod(binding, false); + currentScope.problemReporter().needToEmulateFieldWriteAccess(binding, this); + return; + + } else if (binding.isProtected()) { + + SourceTypeBinding enclosingSourceType; + if (((bits & DepthMASK) != 0) + && binding.declaringClass.getPackage() + != (enclosingSourceType = currentScope.enclosingSourceType()).getPackage()) { + + SourceTypeBinding currentCompatibleType = + (SourceTypeBinding) enclosingSourceType.enclosingTypeAt( + (bits & DepthMASK) >> DepthSHIFT); + syntheticWriteAccessor = + currentCompatibleType.addSyntheticMethod(binding, false); + currentScope.problemReporter().needToEmulateFieldWriteAccess(binding, this); + return; + } + } + // if the binding declaring class is not visible, need special action + // for runtime compatibility on 1.2 VMs : change the declaring class of the binding + // NOTE: from 1.4 on, field's declaring class is touched if any different from receiver type + if (binding.declaringClass != this.receiverType + && !this.receiverType.isArrayType() + && binding.declaringClass != null // array.length + && binding.constant == NotAConstant + && ((currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4 + && binding.declaringClass.id != T_Object) + //no change for Object fields (in case there was) + || !binding.declaringClass.canBeSeenBy(currentScope))) { + this.codegenBinding = + currentScope.enclosingSourceType().getUpdatedFieldBinding( + binding, + (ReferenceBinding) this.receiverType); + } + } + + public TypeBinding resolveType(BlockScope scope) { + + // Answer the signature type of the field. + // constants are propaged when the field is final + // and initialized with a (compile time) constant + + // regular receiver reference + this.receiverType = receiver.resolveType(scope); + if (this.receiverType == null) { + constant = NotAConstant; + return null; + } + // the case receiverType.isArrayType and token = 'length' is handled by the scope API + this.codegenBinding = + this.binding = scope.getField(this.receiverType, token, this); + if (!binding.isValidBinding()) { + constant = NotAConstant; + scope.problemReporter().invalidField(this, this.receiverType); + return null; + } + + if (isFieldUseDeprecated(binding, scope)) + scope.problemReporter().deprecatedField(binding, this); + + // check for this.x in static is done in the resolution of the receiver + constant = + FieldReference.getConstantFor( + binding, + receiver == ThisReference.ThisImplicit, + this, + scope, + 0); + if (receiver != ThisReference.ThisImplicit) + constant = NotAConstant; + + return binding.type; + } + + public void setActualReceiverType(ReferenceBinding receiverType) { + // ignored + } + + public void setDepth(int depth) { + + if (depth > 0) { + bits &= ~DepthMASK; // flush previous depth if any + bits |= (depth & 0xFF) << DepthSHIFT; // encoded on 8 bits + } + } + + public void setFieldIndex(int index) { + // ignored + } + + public String toStringExpression() { + + return receiver.toString() + "." //$NON-NLS-1$ + + new String(token); + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + receiver.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/FloatLiteral.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/FloatLiteral.java new file mode 100644 index 0000000..66e2098 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/FloatLiteral.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class FloatLiteral extends NumberLiteral { + float value; + final static float Float_MIN_VALUE = Float.intBitsToFloat(1); // work-around VAJ problem 1F6IGUU +public FloatLiteral(char[] token, int s, int e) { + super(token, s,e); +} +public void computeConstant() { + + //the source is correctly formated so the exception should never occurs + + Float computedValue; + try { + computedValue = Float.valueOf(String.valueOf(source)); + } catch (NumberFormatException e) { + return; + } + + if (computedValue.doubleValue() > Float.MAX_VALUE){ + return; //may be Infinity + } + if (computedValue.floatValue() < Float_MIN_VALUE){ + // see 1F6IGUU + //only a true 0 can be made of zeros + //1.00000000e-46f is illegal .... + label : for (int i = 0; i < source.length; i++) { + switch (source[i]) { + case '.' : + case 'f' : + case 'F' : + case '0' : + break; + case 'e' : + case 'E' : + break label; //exposant are valid !.... + default : + return; //error + + + } + } + } + constant = Constant.fromValue(value = computedValue.floatValue()); +} +/** + * Code generation for float literal + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + int pc = codeStream.position; + if (valueRequired) + if ((implicitConversion >> 4) == T_float) + codeStream.generateInlinedValue(value); + else + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public TypeBinding literalType(BlockScope scope) { + return FloatBinding; +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope blockScope) { + visitor.visit(this, blockScope); + visitor.endVisit(this, blockScope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ForStatement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ForStatement.java new file mode 100644 index 0000000..e6a5901 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ForStatement.java @@ -0,0 +1,336 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class ForStatement extends Statement { + + public Statement[] initializations; + public Expression condition; + public Statement[] increments; + public Statement action; + + //when there is no local declaration, there is no need of a new scope + //scope is positionned either to a new scope, or to the "upper"scope (see resolveType) + public boolean neededScope; + public BlockScope scope; + + private Label breakLabel, continueLabel; + + // for local variables table attributes + int preCondInitStateIndex = -1; + int condIfTrueInitStateIndex = -1; + int mergedInitStateIndex = -1; + + public ForStatement( + Statement[] initializations, + Expression condition, + Statement[] increments, + Statement action, + boolean neededScope, + int s, + int e) { + + this.sourceStart = s; + this.sourceEnd = e; + this.initializations = initializations; + this.condition = condition; + this.increments = increments; + this.action = action; + this.neededScope = neededScope; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + breakLabel = new Label(); + continueLabel = new Label(); + + // process the initializations + if (initializations != null) { + int count = initializations.length, i = 0; + while (i < count) { + flowInfo = initializations[i++].analyseCode(scope, flowContext, flowInfo); + } + } + preCondInitStateIndex = + currentScope.methodScope().recordInitializationStates(flowInfo); + + boolean conditionIsInlinedToTrue = + condition == null || (condition.constant != NotAConstant && condition.constant.booleanValue() == true); + boolean conditionIsInlinedToFalse = + ! conditionIsInlinedToTrue && (condition.constant != NotAConstant && condition.constant.booleanValue() == false); + + // process the condition + LoopingFlowContext condLoopContext = null; + if (condition != null) { + if (!conditionIsInlinedToTrue) { + flowInfo = + condition.analyseCode( + scope, + (condLoopContext = + new LoopingFlowContext(flowContext, this, null, null, scope)), + flowInfo); + } + } + + // process the action + LoopingFlowContext loopingContext; + FlowInfo actionInfo; + if ((action == null) || action.isEmptyBlock()) { + if (condLoopContext != null) + condLoopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo); + if (conditionIsInlinedToTrue) { + return FlowInfo.DeadEnd; + } else { + if (conditionIsInlinedToFalse){ + continueLabel = null; // for(;false;p()); + } + actionInfo = flowInfo.initsWhenTrue().copy(); + loopingContext = + new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, scope); + } + } else { + loopingContext = + new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, scope); + FlowInfo initsWhenTrue = flowInfo.initsWhenTrue(); + condIfTrueInitStateIndex = + currentScope.methodScope().recordInitializationStates(initsWhenTrue); + + actionInfo = conditionIsInlinedToFalse + ? FlowInfo.DeadEnd // unreachable when condition inlined to false + : initsWhenTrue.copy(); + if (!actionInfo.complainIfUnreachable(action, scope)) { + actionInfo = action.analyseCode(scope, loopingContext, actionInfo); + } + + // code generation can be optimized when no need to continue in the loop + if (((actionInfo == FlowInfo.DeadEnd) || actionInfo.isFakeReachable()) + && ((loopingContext.initsOnContinue == FlowInfo.DeadEnd) + || loopingContext.initsOnContinue.isFakeReachable())) { + continueLabel = null; + } else { + if (condLoopContext != null) + condLoopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo); + loopingContext.complainOnFinalAssignmentsInLoop(scope, actionInfo); + actionInfo = + actionInfo.mergedWith(loopingContext.initsOnContinue.unconditionalInits()); + // for increments + } + } + if ((continueLabel != null) && (increments != null)) { + LoopingFlowContext loopContext = + new LoopingFlowContext(flowContext, this, null, null, scope); + int i = 0, count = increments.length; + while (i < count) + actionInfo = increments[i++].analyseCode(scope, loopContext, actionInfo); + loopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo); + } + + // infinite loop + FlowInfo mergedInfo; + if (conditionIsInlinedToTrue) { + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates( + mergedInfo = loopingContext.initsOnBreak); + return mergedInfo; + } + + //end of loop: either condition false or break + mergedInfo = + flowInfo.initsWhenFalse().unconditionalInits().mergedWith( + loopingContext.initsOnBreak.unconditionalInits()); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + + /** + * For statement code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + + // generate the initializations + if (initializations != null) { + for (int i = 0, max = initializations.length; i < max; i++) { + initializations[i].generateCode(scope, codeStream); + } + } + + // label management + Label actionLabel = new Label(codeStream); + Label conditionLabel = new Label(codeStream); + breakLabel.codeStream = codeStream; + if (continueLabel != null) { + continueLabel.codeStream = codeStream; + } + // jump over the actionBlock + if ((condition != null) + && (condition.constant == NotAConstant) + && !((action == null || action.isEmptyBlock()) && (increments == null))) { + int jumpPC = codeStream.position; + codeStream.goto_(conditionLabel); + codeStream.recordPositionsFrom(jumpPC, condition.sourceStart); + } + // generate the loop action + actionLabel.place(); + if (action != null) { + // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect + if (condIfTrueInitStateIndex != -1) { + // insert all locals initialized inside the condition into the action generated prior to the condition + codeStream.addDefinitelyAssignedVariables( + currentScope, + condIfTrueInitStateIndex); + } + action.generateCode(scope, codeStream); + } + // continuation point + if (continueLabel != null) { + continueLabel.place(); + // generate the increments for next iteration + if (increments != null) { + for (int i = 0, max = increments.length; i < max; i++) { + increments[i].generateCode(scope, codeStream); + } + } + } + + // May loose some local variable initializations : affecting the local variable attributes + if (preCondInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + preCondInitStateIndex); + } + + // generate the condition + conditionLabel.place(); + if ((condition != null) && (condition.constant == NotAConstant)) { + condition.generateOptimizedBoolean(scope, codeStream, actionLabel, null, true); + } else { + if (continueLabel != null) { + codeStream.goto_(actionLabel); + } + } + breakLabel.place(); + + // May loose some local variable initializations : affecting the local variable attributes + if (neededScope) { + codeStream.exitUserScope(scope); + } + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public void resetStateForCodeGeneration() { + + this.breakLabel.resetStateForCodeGeneration(); + this.continueLabel.resetStateForCodeGeneration(); + } + + public void resolve(BlockScope upperScope) { + + // use the scope that will hold the init declarations + scope = neededScope ? new BlockScope(upperScope) : upperScope; + if (initializations != null) + for (int i = 0, length = initializations.length; i < length; i++) + initializations[i].resolve(scope); + if (condition != null) { + TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding); + condition.implicitWidening(type, type); + } + if (increments != null) + for (int i = 0, length = increments.length; i < length; i++) + increments[i].resolve(scope); + if (action != null) + action.resolve(scope); + } + + public String toString(int tab) { + + String s = tabString(tab) + "for ("; //$NON-NLS-1$ + if (!neededScope) + s = s + " //--NO upperscope scope needed\n" + tabString(tab) + " "; //$NON-NLS-2$ //$NON-NLS-1$ + //inits + if (initializations != null) { + for (int i = 0; i < initializations.length; i++) { + //nice only with expressions + s = s + initializations[i].toString(0); + if (i != (initializations.length - 1)) + s = s + " , "; //$NON-NLS-1$ + } + }; + s = s + "; "; //$NON-NLS-1$ + //cond + if (condition != null) + s = s + condition.toStringExpression(); + s = s + "; "; //$NON-NLS-1$ + //updates + if (increments != null) { + for (int i = 0; i < increments.length; i++) { + //nice only with expressions + s = s + increments[i].toString(0); + if (i != (increments.length - 1)) + s = s + " , "; //$NON-NLS-1$ + } + }; + s = s + ") "; //$NON-NLS-1$ + //block + if (action == null) + s = s + "{}"; //$NON-NLS-1$ + else + s = s + "\n" + action.toString(tab + 1); //$NON-NLS-1$ + return s; + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + if (initializations != null) { + int initializationsLength = initializations.length; + for (int i = 0; i < initializationsLength; i++) + initializations[i].traverse(visitor, scope); + } + + if (condition != null) + condition.traverse(visitor, scope); + + if (increments != null) { + int incrementsLength = increments.length; + for (int i = 0; i < incrementsLength; i++) + increments[i].traverse(visitor, scope); + } + + if (action != null) + action.traverse(visitor, scope); + } + visitor.endVisit(this, blockScope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/IfStatement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/IfStatement.java new file mode 100644 index 0000000..2c11637 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/IfStatement.java @@ -0,0 +1,278 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class IfStatement extends Statement { + + //this class represents the case of only one statement in + //either else and/or then branches. + + public Expression condition; + public Statement thenStatement; + public Statement elseStatement; + + boolean thenExit; + + // for local variables table attributes + int thenInitStateIndex = -1; + int elseInitStateIndex = -1; + int mergedInitStateIndex = -1; + + public IfStatement( + Expression condition, + Statement thenStatement, + int s, + int e) { + + this.condition = condition; + this.thenStatement = thenStatement; + sourceStart = s; + sourceEnd = e; + } + + public IfStatement( + Expression condition, + Statement thenStatement, + Statement elseStatement, + int s, + int e) { + + this.condition = condition; + this.thenStatement = thenStatement; + this.elseStatement = elseStatement; + sourceEnd = e; + sourceStart = s; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + FlowInfo thenFlowInfo, elseFlowInfo; + + // process the condition + flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo); + + // process the THEN part + if (thenStatement == null) { + thenFlowInfo = flowInfo.initsWhenTrue(); + } else { + Constant cst; + thenFlowInfo = + ((((cst = condition.constant) != NotAConstant) + && (cst.booleanValue() == false)) + || (((cst = condition.conditionalConstant()) != NotAConstant) + && (cst.booleanValue() == false))) + ? (flowInfo.initsWhenTrue().copy().markAsFakeReachable(true)) + : flowInfo.initsWhenTrue().copy(); + // Save info for code gen + thenInitStateIndex = + currentScope.methodScope().recordInitializationStates(thenFlowInfo); + if (!thenFlowInfo.complainIfUnreachable(thenStatement, currentScope)) { + thenFlowInfo = + thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo); + } + }; + // optimizing the jump around the ELSE part + thenExit = (thenFlowInfo == FlowInfo.DeadEnd) || thenFlowInfo.isFakeReachable(); + + // process the ELSE part + if (elseStatement == null) { + elseFlowInfo = flowInfo.initsWhenFalse(); + } else { + Constant cst; + elseFlowInfo = + ((((cst = condition.constant) != NotAConstant) && (cst.booleanValue() == true)) + || (((cst = condition.conditionalConstant()) != NotAConstant) + && (cst.booleanValue() == true))) + ? (flowInfo.initsWhenFalse().copy().markAsFakeReachable(true)) + : flowInfo.initsWhenFalse().copy(); + // Save info for code gen + elseInitStateIndex = + currentScope.methodScope().recordInitializationStates(elseFlowInfo); + if (!elseFlowInfo.complainIfUnreachable(elseStatement, currentScope)) { + elseFlowInfo = + elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo); + } + } + + // merge THEN & ELSE initializations + FlowInfo mergedInfo; + if ((condition.constant != NotAConstant) + && (condition.constant.booleanValue() == true)) { + // IF (TRUE) + if (thenExit) { + mergedInfo = elseFlowInfo.markAsFakeReachable(true); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } else { + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(thenFlowInfo); + return thenFlowInfo; + } + } else { + // IF (FALSE) + if ((condition.constant != NotAConstant) + && (condition.constant.booleanValue() == false)) { + if (elseFlowInfo.isDeadEnd()) { + mergedInfo = thenFlowInfo.markAsFakeReachable(true); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } else { + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(elseFlowInfo); + return elseFlowInfo; + } + } + } + mergedInfo = thenFlowInfo.mergedWith(elseFlowInfo.unconditionalInits()); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + + /** + * If code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + Label endifLabel = new Label(codeStream); + + // optimizing the then/else part code gen + Constant cst, condCst; + boolean hasThenPart = + !((((cst = condition.constant) != NotAConstant) + && (cst.booleanValue() == false)) + || (thenStatement == null) + || (thenStatement.isEmptyBlock()) + || (((condCst = condition.conditionalConstant()) != NotAConstant) + && (condCst.booleanValue() == false))); + boolean hasElsePart = + !(((cst != NotAConstant) && (cst.booleanValue() == true)) + || (elseStatement == null) + || (elseStatement.isEmptyBlock()) + || (((condCst = condition.conditionalConstant()) != NotAConstant) + && (condCst.booleanValue() == true))); + + if (hasThenPart) { + Label falseLabel; + // generate boolean condition + condition.generateOptimizedBoolean( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + true); + // May loose some local variable initializations : affecting the local variable attributes + if (thenInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + thenInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, thenInitStateIndex); + } + // generate then statement + thenStatement.generateCode(currentScope, codeStream); + // jump around the else statement + if (hasElsePart && !thenExit) { + thenStatement.branchChainTo(endifLabel); + int position = codeStream.position; + codeStream.goto_(endifLabel); + codeStream.updateLastRecordedEndPC(position); + //goto is tagged as part of the thenAction block + } + falseLabel.place(); + } else { + if (hasElsePart) { + // generate boolean condition + condition.generateOptimizedBoolean( + currentScope, + codeStream, + endifLabel, + null, + true); + } else { + // generate condition side-effects + condition.generateCode(currentScope, codeStream, false); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + } + // generate else statement + if (hasElsePart) { + // May loose some local variable initializations : affecting the local variable attributes + if (elseInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + elseInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, elseInitStateIndex); + } + elseStatement.generateCode(currentScope, codeStream); + } + endifLabel.place(); + // May loose some local variable initializations : affecting the local variable attributes + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public void resolve(BlockScope scope) { + + TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding); + condition.implicitWidening(type, type); + if (thenStatement != null) + thenStatement.resolve(scope); + if (elseStatement != null) + elseStatement.resolve(scope); + } + + public String toString(int tab) { + + String inFront, s = tabString(tab); + inFront = s; + s = s + "if (" + condition.toStringExpression() + ") \n"; //$NON-NLS-1$ //$NON-NLS-2$ + s = s + thenStatement.toString(tab + 2) + ";"; //$NON-NLS-1$ + if (elseStatement != null) + s = s + "\n" + inFront + "else\n" + elseStatement.toString(tab + 2) + ";"; //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-3$ + return s; + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + condition.traverse(visitor, blockScope); + if (thenStatement != null) + thenStatement.traverse(visitor, blockScope); + if (elseStatement != null) + elseStatement.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ImportReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ImportReference.java new file mode 100644 index 0000000..9f85770 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ImportReference.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class ImportReference extends AstNode { + + public char[][] tokens; + public long[] sourcePositions; //each entry is using the code : (start<<32) + end + public boolean onDemand = true; //most of the time + public int declarationEnd;// doesn't include an potential trailing comment + public int declarationSourceStart; + public int declarationSourceEnd; + public boolean used; + +public ImportReference(char[][] sources , long[] poss , boolean d) { + tokens = sources ; + sourcePositions = poss ; + onDemand = d; + sourceEnd = (int)(sourcePositions[sourcePositions.length-1] & 0x00000000FFFFFFFF); + sourceStart = (int)(sourcePositions[0]>>>32) ; +} +/** + * @return char[][] + */ +public char[][] getImportName() { + return tokens; +} +public String toString(int tab ){ + + return toString(tab,true); +} +public String toString(int tab, boolean withOnDemand) { + /* when withOnDemand is false, only the name is printed */ + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < tokens.length; i++) { + buffer.append(tokens[i]); + if (i < (tokens.length - 1)) { + buffer.append("."); //$NON-NLS-1$ + } + } + if (withOnDemand && onDemand) { + buffer.append(".*"); //$NON-NLS-1$ + } + return buffer.toString(); +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, CompilationUnitScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Initializer.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Initializer.java new file mode 100644 index 0000000..858198c --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Initializer.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.parser.*; + +public class Initializer extends FieldDeclaration { + + public Block block; + public int lastFieldID; + public int bodyStart; + public Initializer(Block block, int modifiers) { + this.block = block; + this.modifiers = modifiers; + + declarationSourceStart = sourceStart = block.sourceStart; + } + + public FlowInfo analyseCode( + MethodScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + return block.analyseCode(currentScope, flowContext, flowInfo); + } + + /** + * Code generation for a non-static initializer. + * i.e. normal block code gen + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + block.generateCode(currentScope, codeStream); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public boolean isField() { + + return false; + } + + public boolean isStatic() { + + return (modifiers & AccStatic) != 0; + } + + public void parseStatements( + Parser parser, + TypeDeclaration type, + CompilationUnitDeclaration unit) { + + //fill up the method body with statement + parser.parse(this, type, unit); + } + + public void resolve(MethodScope scope) { + + int previous = scope.fieldDeclarationIndex; + try { + scope.fieldDeclarationIndex = lastFieldID; + if (isStatic()) { + ReferenceBinding declaringType = scope.enclosingSourceType(); + if (declaringType.isNestedType() && !declaringType.isStatic()) + scope.problemReporter().innerTypesCannotDeclareStaticInitializers( + declaringType, + this); + } + block.resolve(scope); + } finally { + scope.fieldDeclarationIndex = previous; + } + } + + public String toString(int tab) { + + if (modifiers != 0) { + StringBuffer buffer = new StringBuffer(); + buffer.append(tabString(tab)); + buffer.append(modifiersString(modifiers)); + buffer.append("{\n"); //$NON-NLS-1$ + buffer.append(block.toStringStatements(tab)); + buffer.append(tabString(tab)); + buffer.append("}"); //$NON-NLS-1$ + return buffer.toString(); + } else { + return block.toString(tab); + } + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, MethodScope scope) { + + if (visitor.visit(this, scope)) { + block.traverse(visitor, scope); + } + visitor.visit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/InnerTypeDeclaration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/InnerTypeDeclaration.java new file mode 100644 index 0000000..b1496f8 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/InnerTypeDeclaration.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.CompilationResult; + +public class InnerTypeDeclaration extends TypeDeclaration { + + public InnerTypeDeclaration(CompilationResult compilationResult){ + super(compilationResult); + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/InstanceOfExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/InstanceOfExpression.java new file mode 100644 index 0000000..db4cd45 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/InstanceOfExpression.java @@ -0,0 +1,248 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class InstanceOfExpression extends OperatorExpression { + + public Expression expression; + public TypeReference type; + + public InstanceOfExpression( + Expression expression, + TypeReference type, + int operator) { + + this.expression = expression; + this.type = type; + this.bits |= operator << OperatorSHIFT; + this.sourceStart = expression.sourceStart; + this.sourceEnd = type.sourceEnd; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + return expression + .analyseCode(currentScope, flowContext, flowInfo) + .unconditionalInits(); + } + + public final boolean areTypesCastCompatible( + BlockScope scope, + TypeBinding castTb, + TypeBinding expressionTb) { + + // see specifications p.68 + //A more cpmplete version of this method is provided on + //CastExpression (it deals with constant and need runtime checkcast) + + //by grammatical construction, the first test is ALWAYS false + //if (castTb.isBaseType()) + //{ if (expressionTb.isBaseType()) + // { if (expression.isConstantValueOfTypeAssignableToType(expressionTb,castTb)) + // { return true;} + // else + // { if (expressionTb==castTb) + // { return true;} + // else + // { if (scope.areTypesCompatible(expressionTb,castTb)) + // { return true; } + // + // if (BaseTypeBinding.isNarrowing(castTb.id,expressionTb.id)) + // { return true;} + // return false;}}} + // else + // { return false; }} + //else + { //-------------checkcast to something which is NOT a basetype---------------------------------- + + if (NullBinding == expressionTb) + //null is compatible with every thing .... + { + return true; + } + if (expressionTb.isArrayType()) { + if (castTb.isArrayType()) { + //------- (castTb.isArray) expressionTb.isArray ----------- + TypeBinding expressionEltTb = ((ArrayBinding) expressionTb).elementsType(scope); + if (expressionEltTb.isBaseType()) + // <---stop the recursion------- + return ((ArrayBinding) castTb).elementsType(scope) == expressionEltTb; + //recursivly on the elts... + return areTypesCastCompatible( + scope, + ((ArrayBinding) castTb).elementsType(scope), + expressionEltTb); + } + if (castTb.isClass()) { + //------(castTb.isClass) expressionTb.isArray --------------- + if (scope.isJavaLangObject(castTb)) + return true; + return false; + } + if (castTb.isInterface()) { + //------- (castTb.isInterface) expressionTb.isArray ----------- + if (scope.isJavaLangCloneable(castTb) || scope.isJavaIoSerializable(castTb)) { + return true; + } + return false; + } + + return false; + } + if (expressionTb.isBaseType()) { + return false; + } + if (expressionTb.isClass()) { + if (castTb.isArrayType()) { + // ---- (castTb.isArray) expressionTb.isClass ------- + if (scope.isJavaLangObject(expressionTb)) { + return true; + } else { + return false; + } + } + if (castTb.isClass()) { // ----- (castTb.isClass) expressionTb.isClass ------ + if (scope.areTypesCompatible(expressionTb, castTb)) + return true; + else { + if (scope.areTypesCompatible(castTb, expressionTb)) { + return true; + } + return false; + } + } + if (castTb.isInterface()) { + // ----- (castTb.isInterface) expressionTb.isClass ------- + if (((ReferenceBinding) expressionTb).isFinal()) { + //no subclass for expressionTb, thus compile-time check is valid + if (scope.areTypesCompatible(expressionTb, castTb)) + return true; + return false; + } else { + return true; + } + } + + return false; + } + if (expressionTb.isInterface()) { + if (castTb.isArrayType()) { + // ----- (castTb.isArray) expressionTb.isInterface ------ + if (scope.isJavaLangCloneable(expressionTb) + || scope.isJavaIoSerializable(expressionTb)) + //potential runtime error + { + return true; + } + return false; + } + if (castTb.isClass()) { + // ----- (castTb.isClass) expressionTb.isInterface -------- + if (scope.isJavaLangObject(castTb)) + return true; + if (((ReferenceBinding) castTb).isFinal()) { + //no subclass for castTb, thus compile-time check is valid + if (scope.areTypesCompatible(castTb, expressionTb)) { + return true; + } + return false; + } + return true; + } + if (castTb.isInterface()) { + // ----- (castTb.isInterface) expressionTb.isInterface ------- + if (castTb != expressionTb + && (Scope.compareTypes(castTb, expressionTb) == NotRelated)) { + MethodBinding[] castTbMethods = ((ReferenceBinding) castTb).methods(); + int castTbMethodsLength = castTbMethods.length; + MethodBinding[] expressionTbMethods = + ((ReferenceBinding) expressionTb).methods(); + int expressionTbMethodsLength = expressionTbMethods.length; + for (int i = 0; i < castTbMethodsLength; i++) { + for (int j = 0; j < expressionTbMethodsLength; j++) { + if (castTbMethods[i].selector == expressionTbMethods[j].selector) { + if (castTbMethods[i].returnType != expressionTbMethods[j].returnType) { + if (castTbMethods[i].areParametersEqual(expressionTbMethods[j])) { + return false; + } + } + } + } + } + } + return true; + } + + return false; + } + + return false; + } + } + /** + * Code generation for instanceOfExpression + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + expression.generateCode(currentScope, codeStream, true); + codeStream.instance_of(type.binding); + if (!valueRequired) + codeStream.pop(); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public TypeBinding resolveType(BlockScope scope) { + + constant = NotAConstant; + TypeBinding expressionTb = expression.resolveType(scope); + TypeBinding checkTb = type.resolveType(scope); + if (expressionTb == null || checkTb == null) + return null; + + if (!areTypesCastCompatible(scope, checkTb, expressionTb)) { + scope.problemReporter().notCompatibleTypesError(this, expressionTb, checkTb); + return null; + } + this.typeBinding = BooleanBinding; + return BooleanBinding; + } + + public String toStringExpressionNoParenthesis() { + + return expression.toStringExpression() + " instanceof " + //$NON-NLS-1$ + type.toString(0); + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + expression.traverse(visitor, scope); + type.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/IntLiteral.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/IntLiteral.java new file mode 100644 index 0000000..26bcec3 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/IntLiteral.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class IntLiteral extends NumberLiteral { + public int value; + + public static final IntLiteral + One = new IntLiteral(new char[]{'1'},0,0,1);//used for ++ and -- + + static final Constant FORMAT_ERROR = new DoubleConstant(1.0/0.0); // NaN; +public IntLiteral(char[] token, int s, int e) { + super(token, s,e); +} +public IntLiteral(char[] token, int s,int e, int value) { + this(token, s,e); + this.value = value; +} +public IntLiteral(int intValue) { + //special optimized constructor : the cst is the argument + + //value that should not be used + // tokens = null ; + // sourceStart = 0; + // sourceEnd = 0; + super(null,0,0); + constant = Constant.fromValue(intValue); + value = intValue; + +} +public void computeConstant() { + //a special constant is use for the potential Integer.MAX_VALUE+1 + //which is legal if used with a - as prefix....cool.... + //notice that Integer.MIN_VALUE == -2147483648 + + long MAX = Integer.MAX_VALUE; + if (this == One) { constant = Constant.One; return ;} + + int length = source.length; + long computedValue = 0L; + if (source[0] == '0') + { MAX = 0xFFFFFFFFL ; //a long in order to be positive ! + if (length == 1) { constant = Constant.fromValue(0); return ;} + final int shift,radix; + int j ; + if ( (source[1] == 'x') | (source[1] == 'X') ) + { shift = 4 ; j = 2; radix = 16;} + else + { shift = 3 ; j = 1; radix = 8;} + while (source[j]=='0') + { j++; //jump over redondant zero + if (j == length) + { //watch for 000000000000000000 :-( + constant = Constant.fromValue(value = (int)computedValue); + return ;}} + + while (j MAX) return /*constant stays null*/ ;}} + else + { //-----------regular case : radix = 10----------- + for (int i = 0 ; i < length;i++) + { int digitValue ; + if ((digitValue = Character.digit(source[i],10)) < 0 ) + { constant = FORMAT_ERROR; return ;} + computedValue = 10*computedValue + digitValue; + if (computedValue > MAX) return /*constant stays null*/ ; }} + + constant = Constant.fromValue(value = (int)computedValue); + +} +/** + * Code generation for int literal + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + int pc = codeStream.position; + if (valueRequired) + if ((implicitConversion >> 4) == T_int) + codeStream.generateInlinedValue(value); + else + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public TypeBinding literalType(BlockScope scope) { + return IntBinding; +} +public final boolean mayRepresentMIN_VALUE(){ + //a special autorized int literral is 2147483648 + //which is ONE over the limit. This special case + //only is used in combinaison with - to denote + //the minimal value of int -2147483648 + + return ((source.length == 10) && + (source[0] == '2') && + (source[1] == '1') && + (source[2] == '4') && + (source[3] == '7') && + (source[4] == '4') && + (source[5] == '8') && + (source[6] == '3') && + (source[7] == '6') && + (source[8] == '4') && + (source[9] == '8'));} +public TypeBinding resolveType(BlockScope scope) { + // the format may be incorrect while the scanner could detect + // such an error only on painfull tests...easier and faster here + + TypeBinding tb = super.resolveType(scope); + if (constant == FORMAT_ERROR) { + constant = NotAConstant; + scope.problemReporter().constantOutOfFormat(this); + return null; + } + return tb; +} +public String toStringExpression(){ + + if (source == null) + /* special optimized IntLiteral that are created by the compiler */ + return String.valueOf(value); + + return super.toStringExpression();} +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/IntLiteralMinValue.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/IntLiteralMinValue.java new file mode 100644 index 0000000..f21d8af --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/IntLiteralMinValue.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.impl.*; + +public class IntLiteralMinValue extends IntLiteral { + + final static char[] CharValue = new char[]{'-','2','1','4','7','4','8','3','6','4','8'}; + final static Constant MIN_VALUE = Constant.fromValue(Integer.MIN_VALUE) ; + +public IntLiteralMinValue() { + super(CharValue,0,0,Integer.MIN_VALUE); + constant = MIN_VALUE; +} +public void computeConstant(){ + + /*precomputed at creation time*/ } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/LabeledStatement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/LabeledStatement.java new file mode 100644 index 0000000..8998f6b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/LabeledStatement.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class LabeledStatement extends Statement { + + public Statement statement; + public char[] label; + public Label targetLabel; + + // for local variables table attributes + int mergedInitStateIndex = -1; + + /** + * LabeledStatement constructor comment. + */ + public LabeledStatement(char[] l, Statement st, int s, int e) { + + this.statement = st; + this.label = l; + this.sourceStart = s; + this.sourceEnd = e; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // need to stack a context to store explicit label, answer inits in case of normal completion merged + // with those relative to the exit path from break statement occurring inside the labeled statement. + if (statement == null) { + return flowInfo; + } else { + LabelFlowContext labelContext; + FlowInfo mergedInfo = + statement + .analyseCode( + currentScope, + (labelContext = + new LabelFlowContext( + flowContext, + this, + label, + (targetLabel = new Label()), + currentScope)), + flowInfo) + .mergedWith(labelContext.initsOnBreak); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + } + + public AstNode concreteStatement() { + + return statement.concreteStatement(); + } + + /** + * Code generation for labeled statement + * + * may not need actual source positions recording + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + int pc = codeStream.position; + if (targetLabel != null) { + targetLabel.codeStream = codeStream; + if (statement != null) { + statement.generateCode(currentScope, codeStream); + } + targetLabel.place(); + } + // May loose some local variable initializations : affecting the local variable attributes + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public void resolve(BlockScope scope) { + + statement.resolve(scope); + } + + public String toString(int tab) { + + String s = tabString(tab); + s += new String(label) + ": " + statement.toString(0); //$NON-NLS-1$ + return s; + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + statement.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } + + public void resetStateForCodeGeneration() { + + this.targetLabel.resetStateForCodeGeneration(); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Literal.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Literal.java new file mode 100644 index 0000000..2e1e638 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Literal.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public abstract class Literal extends Expression { + + +public Literal(int s,int e) { + sourceStart = s ; + sourceEnd= e; +} +public abstract void computeConstant() ; + //ON ERROR constant STAYS NULL +public abstract TypeBinding literalType(BlockScope scope); +public TypeBinding resolveType(BlockScope scope) { + // compute the real value, which must range its type's range + + computeConstant(); + if (constant == null) { + scope.problemReporter().constantOutOfRange(this); + constant = Constant.NotAConstant; + return null; + } + return literalType(scope); +} +public abstract char[] source() ; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/LocalDeclaration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/LocalDeclaration.java new file mode 100644 index 0000000..853e580 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/LocalDeclaration.java @@ -0,0 +1,206 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class LocalDeclaration extends AbstractVariableDeclaration { + + public LocalVariableBinding binding; + + public LocalDeclaration( + Expression expr, + char[] name, + int sourceStart, + int sourceEnd) { + + initialization = expr; + this.name = name; + this.sourceStart = sourceStart; + this.sourceEnd = sourceEnd; + if (initialization != null) { + this.declarationSourceEnd = initialization.sourceEnd; + } else { + this.declarationSourceEnd = sourceEnd; + } + this.declarationEnd = this.declarationSourceEnd; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // record variable initialization if any + if (!flowInfo.isDeadEnd() && !flowInfo.isFakeReachable()) { + bits |= IsLocalDeclarationReachableMASK; // only set if actually reached + } + if (initialization == null) + return flowInfo; + flowInfo = + initialization + .analyseCode(currentScope, flowContext, flowInfo) + .unconditionalInits(); + flowInfo.markAsDefinitelyAssigned(binding); + return flowInfo; + } + + public void checkModifiers() { + //only potential valid modifier is <> + + if (((modifiers & AccJustFlag) | AccFinal) != AccFinal) + //AccModifierProblem -> other (non-visibility problem) + //AccAlternateModifierProblem -> duplicate modifier + //AccModifierProblem | AccAlternateModifierProblem -> visibility problem" + // -x-1 returns the bitInvert + + modifiers = + (modifiers & (-AccAlternateModifierProblem - 1)) | AccModifierProblem; + } + + /** + * Code generation for a local declaration: + * i.e. normal assignment to a local variable + unused variable handling + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + Constant inlinedValue; + // something to initialize? + if (binding.resolvedPosition != -1) { + codeStream.addVisibleLocalVariable(binding); + } + if (initialization != null) { + // initialize to constant value? + if ((inlinedValue = initialization.constant) != NotAConstant) { + // forget initializing unused or final locals set to constant value (final ones are inlined) + if (binding.resolvedPosition != -1) { // may need to preserve variable + int initPC = codeStream.position; + codeStream.generateConstant(inlinedValue, initialization.implicitConversion); + codeStream.recordPositionsFrom(initPC, initialization.sourceStart); + codeStream.store(binding, false); + binding.recordInitializationStartPC(codeStream.position); + // codeStream.lastInitStateIndexWhenRemovingInits = -2; // reinitialize remove index + // codeStream.lastInitStateIndexWhenAddingInits = -2; // reinitialize add index + } + } else { // initializing to non-constant value + initialization.generateCode(currentScope, codeStream, true); + // if binding unused generate then discard the value + if (binding.resolvedPosition != -1) { + codeStream.store(binding, false); + if (binding.initializationCount == 0) { + /* Variable may have been initialized during the code initializing it + e.g. int i = (i = 1); + */ + binding.recordInitializationStartPC(codeStream.position); + // codeStream.lastInitStateIndexWhenRemovingInits = -2; // reinitialize remove index + // codeStream.lastInitStateIndexWhenAddingInits = -2; // reinitialize add index + } + } else { + if ((binding.type == LongBinding) || (binding.type == DoubleBinding)) { + codeStream.pop2(); + } else { + codeStream.pop(); + } + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public String name() { + + return String.valueOf(name); + } + + public void resolve(BlockScope scope) { + + // create a binding and add it to the scope + TypeBinding tb = type.resolveType(scope); + + checkModifiers(); + + if (tb != null) { + if (tb == VoidBinding) { + scope.problemReporter().variableTypeCannotBeVoid(this); + return; + } + if (tb.isArrayType() && ((ArrayBinding) tb).leafComponentType == VoidBinding) { + scope.problemReporter().variableTypeCannotBeVoidArray(this); + return; + } + } + + // duplicate checks + if ((binding = scope.duplicateName(name)) != null) { + // the name already exists... may carry on with the first binding... + scope.problemReporter().redefineLocal(this); + } else { + binding = new LocalVariableBinding(this, tb, modifiers, false); + scope.addLocalVariable(binding); + binding.constant = NotAConstant; + // allow to recursivelly target the binding.... + // the correct constant is harmed if correctly computed at the end of this method + } + + if (tb == null) { + if (initialization != null) + initialization.resolveType(scope); // want to report all possible errors + return; + } + + // store the constant for final locals + if (initialization != null) { + if (initialization instanceof ArrayInitializer) { + TypeBinding initTb = initialization.resolveTypeExpecting(scope, tb); + if (initTb != null) { + ((ArrayInitializer) initialization).binding = (ArrayBinding) initTb; + initialization.implicitWidening(tb, initTb); + } + } else { + TypeBinding initTb = initialization.resolveType(scope); + if (initTb != null) { + if (initialization.isConstantValueOfTypeAssignableToType(initTb, tb) + || (tb.isBaseType() && BaseTypeBinding.isWidening(tb.id, initTb.id)) + || scope.areTypesCompatible(initTb, tb)) + initialization.implicitWidening(tb, initTb); + else + scope.problemReporter().typeMismatchError(initTb, tb, this); + } + } + + // change the constant in the binding when it is final + // (the optimization of the constant propagation will be done later on) + // cast from constant actual type to variable type + binding.constant = + binding.isFinal() + ? initialization.constant.castTo((tb.id << 4) + initialization.constant.typeID()) + : NotAConstant; + } + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + type.traverse(visitor, scope); + if (initialization != null) + initialization.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/LocalTypeDeclaration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/LocalTypeDeclaration.java new file mode 100644 index 0000000..6f286c9 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/LocalTypeDeclaration.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.CompilationResult; +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; + +public class LocalTypeDeclaration extends InnerTypeDeclaration { + public AbstractMethodDeclaration enclosingMethod; + +public LocalTypeDeclaration(CompilationResult compilationResult){ + super(compilationResult); +} + +/** + * Iteration for a local innertype + * + */ +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope blockScope) { + if (ignoreFurtherInvestigation) + return; + try { + if (visitor.visit(this, blockScope)) { + if (superclass != null) + superclass.traverse(visitor, scope); + if (superInterfaces != null) { + int superInterfaceLength = superInterfaces.length; + for (int i = 0; i < superInterfaceLength; i++) + superInterfaces[i].traverse(visitor, scope); + } + if (memberTypes != null) { + int memberTypesLength = memberTypes.length; + for (int i = 0; i < memberTypesLength; i++) + memberTypes[i].traverse(visitor, scope); + } + if (fields != null) { + int fieldsLength = fields.length; + for (int i = 0; i < fieldsLength; i++) { + FieldDeclaration field; + if ((field = fields[i]).isStatic()) { + // local type cannot have static fields + } else { + field.traverse(visitor, initializerScope); + } + } + } + if (methods != null) { + int methodsLength = methods.length; + for (int i = 0; i < methodsLength; i++) + methods[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, blockScope); + } catch (AbortType e) { + } +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/LongLiteral.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/LongLiteral.java new file mode 100644 index 0000000..021d950 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/LongLiteral.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class LongLiteral extends NumberLiteral { + long value; + + static final Constant FORMAT_ERROR = new DoubleConstant(1.0/0.0); // NaN; + +public LongLiteral(char[] token, int s,int e) { + super(token, s,e); +} +public LongLiteral(char[] token, int s,int e, long value) { + this(token, s,e); + this.value = value; +} +public void computeConstant() { + //the overflow (when radix=10) is tested using the fact that + //the value should always grow during its computation + + int length = source.length - 1; //minus one because the last char is 'l' or 'L' + + long computedValue ; + if (source[0] == '0') + { if (length == 1) { constant = Constant.fromValue(0L); return; } + final int shift,radix; + int j ; + if ( (source[1] == 'x') | (source[1] == 'X') ) + { shift = 4 ; j = 2; radix = 16;} + else + { shift = 3 ; j = 1; radix = 8;} + int nbDigit = 0; + while (source[j]=='0') + { j++; //jump over redondant zero + if ( j == length) + { //watch for 0000000000000L + constant = Constant.fromValue(value = 0L); + return ;}} + + int digitValue ; + if ((digitValue = Character.digit(source[j++],radix)) < 0 ) + { constant = FORMAT_ERROR; return ;} + if (digitValue >= 8) nbDigit = 4; + else if (digitValue >= 4) nbDigit = 3; + else if (digitValue >= 2) nbDigit = 2; + else nbDigit = 1; //digitValue is not 0 + computedValue = digitValue ; + while (j 64) return /*constant stays null*/ ; + computedValue = (computedValue< computedValue) return /*constant stays null*/;}} + + constant = Constant.fromValue(value = computedValue); +} +/** + * Code generation for long literal + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + int pc = codeStream.position; + if (valueRequired) + if ((implicitConversion >> 4) == T_long) + codeStream.generateInlinedValue(value); + else + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public TypeBinding literalType(BlockScope scope) { + return LongBinding; +} +public final boolean mayRepresentMIN_VALUE(){ + //a special autorized int literral is 9223372036854775808L + //which is ONE over the limit. This special case + //only is used in combinaison with - to denote + //the minimal value of int -9223372036854775808L + + return ((source.length == 20) && + (source[0] == '9') && + (source[1] == '2') && + (source[2] == '2') && + (source[3] == '3') && + (source[4] == '3') && + (source[5] == '7') && + (source[6] == '2') && + (source[7] == '0') && + (source[8] == '3') && + (source[9] == '6') && + (source[10] == '8') && + (source[11] == '5') && + (source[12] == '4') && + (source[13] == '7') && + (source[14] == '7') && + (source[15] == '5') && + (source[16] == '8') && + (source[17] == '0') && + (source[18] == '8'));} +public TypeBinding resolveType(BlockScope scope) { + // the format may be incorrect while the scanner could detect + // such error only on painfull tests...easier and faster here + + TypeBinding tb = super.resolveType(scope); + if (constant == FORMAT_ERROR) { + constant = NotAConstant; + scope.problemReporter().constantOutOfFormat(this); + return null; + } + return tb; +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/LongLiteralMinValue.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/LongLiteralMinValue.java new file mode 100644 index 0000000..eea131b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/LongLiteralMinValue.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.impl.*; + +public class LongLiteralMinValue extends LongLiteral { + + final static char[] CharValue = new char[]{'-', '9','2','2','3','3','7','2','0','3','6','8','5','4','7','7','5','8','0','8','L'}; + final static Constant MIN_VALUE = Constant.fromValue(Long.MIN_VALUE) ; + +public LongLiteralMinValue(){ + super(CharValue,0,0,Long.MIN_VALUE); + constant = MIN_VALUE; +} +public void computeConstant() { + + /*precomputed at creation time*/} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/MagicLiteral.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/MagicLiteral.java new file mode 100644 index 0000000..95a3bfb --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/MagicLiteral.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +public abstract class MagicLiteral extends Literal { +public MagicLiteral(int s , int e) { + super(s,e); +} +public boolean isValidJavaStatement(){ + //should never be reach, but with a bug in the ast tree.... + //see comment on the Statement class + + return false ;} +/** + * source method comment. + */ +public char[] source() { + return null; +} +public String toStringExpression(){ + + return new String(source()) ; } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/MemberTypeDeclaration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/MemberTypeDeclaration.java new file mode 100644 index 0000000..25debb4 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/MemberTypeDeclaration.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.CompilationResult; +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.lookup.ClassScope; +import net.sourceforge.phpdt.internal.compiler.problem.AbortType; + +public class MemberTypeDeclaration extends InnerTypeDeclaration { + public TypeDeclaration enclosingType; + +public MemberTypeDeclaration(CompilationResult compilationResult){ + super(compilationResult); +} +/** + * Iteration for a member innertype + * + */ +public void traverse(IAbstractSyntaxTreeVisitor visitor, ClassScope classScope) { + if (ignoreFurtherInvestigation) + return; + try { + if (visitor.visit(this, classScope)) { + if (superclass != null) + superclass.traverse(visitor, scope); + if (superInterfaces != null) { + int superInterfaceLength = superInterfaces.length; + for (int i = 0; i < superInterfaceLength; i++) + superInterfaces[i].traverse(visitor, scope); + } + if (memberTypes != null) { + int memberTypesLength = memberTypes.length; + for (int i = 0; i < memberTypesLength; i++) + memberTypes[i].traverse(visitor, scope); + } + if (fields != null) { + int fieldsLength = fields.length; + for (int i = 0; i < fieldsLength; i++) { + FieldDeclaration field; + if ((field = fields[i]).isStatic()) { + field.traverse(visitor, staticInitializerScope); + } else { + field.traverse(visitor, initializerScope); + } + } + } + if (methods != null) { + int methodsLength = methods.length; + for (int i = 0; i < methodsLength; i++) + methods[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, classScope); + } catch (AbortType e) { + } +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/MessageSend.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/MessageSend.java new file mode 100644 index 0000000..fd761cc --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/MessageSend.java @@ -0,0 +1,307 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class MessageSend extends Expression implements InvocationSite { + public Expression receiver ; + public char[] selector ; + public Expression[] arguments ; + public MethodBinding binding, codegenBinding; + + public long nameSourcePosition ; //(start<<32)+end + + MethodBinding syntheticAccessor; + + public TypeBinding receiverType, qualifyingType; + +public MessageSend() { + +} +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + + flowInfo = receiver.analyseCode(currentScope, flowContext, flowInfo, !binding.isStatic()).unconditionalInits(); + if (arguments != null) { + int length = arguments.length; + for (int i = 0; i < length; i++) { + flowInfo = arguments[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + } + } + ReferenceBinding[] thrownExceptions; + if ((thrownExceptions = binding.thrownExceptions) != NoExceptions) { + // must verify that exceptions potentially thrown by this expression are caught in the method + flowContext.checkExceptionHandlers(thrownExceptions, this, flowInfo, currentScope); + } + // if invoking through an enclosing instance, then must perform the field generation -- only if reachable + manageEnclosingInstanceAccessIfNecessary(currentScope); + manageSyntheticAccessIfNecessary(currentScope); + return flowInfo; +} +/** + * MessageSend code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + + int pc = codeStream.position; + + // generate receiver/enclosing instance access + boolean isStatic = codegenBinding.isStatic(); + // outer access ? + if (!isStatic && ((bits & DepthMASK) != 0) && (receiver == ThisReference.ThisImplicit)){ + // outer method can be reached through emulation if implicit access + Object[] path = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)); + if (path == null) { + // emulation was not possible (should not happen per construction) + currentScope.problemReporter().needImplementation(); + } else { + codeStream.generateOuterAccess(path, this, currentScope); + } + } else { + receiver.generateCode(currentScope, codeStream, !isStatic); + } + // generate arguments + if (arguments != null){ + for (int i = 0, max = arguments.length; i < max; i++){ + arguments[i].generateCode(currentScope, codeStream, true); + } + } + // actual message invocation + if (syntheticAccessor == null){ + if (isStatic){ + codeStream.invokestatic(codegenBinding); + } else { + if( (receiver.isSuper()) || codegenBinding.isPrivate()){ + codeStream.invokespecial(codegenBinding); + } else { + if (codegenBinding.declaringClass.isInterface()){ + codeStream.invokeinterface(codegenBinding); + } else { + codeStream.invokevirtual(codegenBinding); + } + } + } + } else { + codeStream.invokestatic(syntheticAccessor); + } + // operation on the returned value + if (valueRequired){ + // implicit conversion if necessary + codeStream.generateImplicitConversion(implicitConversion); + } else { + // pop return value if any + switch(binding.returnType.id){ + case T_long : + case T_double : + codeStream.pop2(); + break; + case T_void : + break; + default: + codeStream.pop(); + } + } + codeStream.recordPositionsFrom(pc, (int)(this.nameSourcePosition >>> 32)); // highlight selector +} +public boolean isSuperAccess() { + return receiver.isSuper(); +} +public boolean isTypeAccess() { + return receiver != null && receiver.isTypeReference(); +} +public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) { + if (((bits & DepthMASK) != 0) && !binding.isStatic() && (receiver == ThisReference.ThisImplicit)) { + ReferenceBinding compatibleType = currentScope.enclosingSourceType(); + // the declaringClass of the target binding must be compatible with the enclosing + // type at levels outside + for (int i = 0, depth = (bits & DepthMASK) >> DepthSHIFT; i < depth; i++) { + compatibleType = compatibleType.enclosingType(); + } + currentScope.emulateOuterAccess((SourceTypeBinding) compatibleType, false); // request cascade of accesses + } +} +public void manageSyntheticAccessIfNecessary(BlockScope currentScope){ + + if (binding.isPrivate()){ + + // depth is set for both implicit and explicit access (see MethodBinding#canBeSeenBy) + if (currentScope.enclosingSourceType() != binding.declaringClass){ + + syntheticAccessor = ((SourceTypeBinding)binding.declaringClass).addSyntheticMethod(binding); + currentScope.problemReporter().needToEmulateMethodAccess(binding, this); + return; + } + + } else if (receiver instanceof QualifiedSuperReference){ // qualified super + + // qualified super need emulation always + SourceTypeBinding destinationType = (SourceTypeBinding)(((QualifiedSuperReference)receiver).currentCompatibleType); + syntheticAccessor = destinationType.addSyntheticMethod(binding); + currentScope.problemReporter().needToEmulateMethodAccess(binding, this); + return; + + } else if (binding.isProtected()){ + + SourceTypeBinding enclosingSourceType; + if (((bits & DepthMASK) != 0) + && binding.declaringClass.getPackage() + != (enclosingSourceType = currentScope.enclosingSourceType()).getPackage()){ + + SourceTypeBinding currentCompatibleType = (SourceTypeBinding)enclosingSourceType.enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT); + syntheticAccessor = currentCompatibleType.addSyntheticMethod(binding); + currentScope.problemReporter().needToEmulateMethodAccess(binding, this); + return; + } + } + // if the binding declaring class is not visible, need special action + // for runtime compatibility on 1.2 VMs : change the declaring class of the binding + // NOTE: from 1.4 on, method's declaring class is touched if any different from receiver type + // and not from Object or implicit static method call. + if (binding.declaringClass != this.qualifyingType + && !this.qualifyingType.isArrayType() + && ((currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4 + && (receiver != ThisReference.ThisImplicit || !binding.isStatic()) + && binding.declaringClass.id != T_Object) // no change for Object methods + || !binding.declaringClass.canBeSeenBy(currentScope))) { + + this.codegenBinding = currentScope.enclosingSourceType().getUpdatedMethodBinding(binding, (ReferenceBinding) this.qualifyingType); + } +} + +public TypeBinding resolveType(BlockScope scope) { + // Answer the signature return type + // Base type promotion + + constant = NotAConstant; + this.qualifyingType = this.receiverType = receiver.resolveType(scope); + + // will check for null after args are resolved + TypeBinding[] argumentTypes = NoParameters; + if (arguments != null) { + boolean argHasError = false; // typeChecks all arguments + int length = arguments.length; + argumentTypes = new TypeBinding[length]; + for (int i = 0; i < length; i++){ + if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null){ + argHasError = true; + } + } + if (argHasError){ + MethodBinding closestMethod = null; + if(receiverType instanceof ReferenceBinding) { + // record any selector match, for clients who may still need hint about possible method match + this.codegenBinding = this.binding = scope.findMethod((ReferenceBinding)receiverType, selector, new TypeBinding[]{}, this); + } + return null; + } + } + if (this.receiverType == null) + return null; + + // base type cannot receive any message + if (this.receiverType.isBaseType()) { + scope.problemReporter().errorNoMethodFor(this, this.receiverType, argumentTypes); + return null; + } + + this.codegenBinding = this.binding = + receiver == ThisReference.ThisImplicit + ? scope.getImplicitMethod(selector, argumentTypes, this) + : scope.getMethod(this.receiverType, selector, argumentTypes, this); + if (!binding.isValidBinding()) { + if (binding.declaringClass == null) { + if (this.receiverType instanceof ReferenceBinding) { + binding.declaringClass = (ReferenceBinding) this.receiverType; + } else { // really bad error .... + scope.problemReporter().errorNoMethodFor(this, this.receiverType, argumentTypes); + return null; + } + } + scope.problemReporter().invalidMethod(this, binding); + // record the closest match, for clients who may still need hint about possible method match + if (binding.problemId() == ProblemReasons.NotFound){ + this.codegenBinding = this.binding = ((ProblemMethodBinding)binding).closestMatch; + } + return null; + } + if (!binding.isStatic()) { + // the "receiver" must not be a type, i.e. a NameReference that the TC has bound to a Type + if (receiver instanceof NameReference) { + if ((((NameReference) receiver).bits & BindingIds.TYPE) != 0) { + scope.problemReporter().mustUseAStaticMethod(this, binding); + return null; + } + } + } + if (arguments != null) + for (int i = 0; i < arguments.length; i++) + arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]); + + //-------message send that are known to fail at compile time----------- + if (binding.isAbstract()) { + if (receiver.isSuper()) { + scope.problemReporter().cannotDireclyInvokeAbstractMethod(this, binding); + return null; + } + // abstract private methods cannot occur nor abstract static............ + } + if (isMethodUseDeprecated(binding, scope)) + scope.problemReporter().deprecatedMethod(binding, this); + + return binding.returnType; +} +public void setActualReceiverType(ReferenceBinding receiverType) { + this.qualifyingType = receiverType; +} +public void setDepth(int depth) { + if (depth > 0) { + bits &= ~DepthMASK; // flush previous depth if any + bits |= (depth & 0xFF) << DepthSHIFT; // encoded on 8 bits + } +} +public void setFieldIndex(int depth) { + // ignore for here +} + +public String toStringExpression(){ + + String s = ""; //$NON-NLS-1$ + if (receiver != ThisReference.ThisImplicit) + s = s + receiver.toStringExpression()+"."; //$NON-NLS-1$ + s = s + new String(selector) + "(" ; //$NON-NLS-1$ + if (arguments != null) + for (int i = 0; i < arguments.length ; i ++) + { s = s + arguments[i].toStringExpression(); + if ( i != arguments.length -1 ) s = s + " , " ;};; //$NON-NLS-1$ + s =s + ")" ; //$NON-NLS-1$ + return s; +} + +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope blockScope) { + if (visitor.visit(this, blockScope)) { + receiver.traverse(visitor, blockScope); + if (arguments != null) { + int argumentsLength = arguments.length; + for (int i = 0; i < argumentsLength; i++) + arguments[i].traverse(visitor, blockScope); + } + } + visitor.endVisit(this, blockScope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/MethodDeclaration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/MethodDeclaration.java new file mode 100644 index 0000000..45def4b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/MethodDeclaration.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.CompilationResult; +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.parser.*; +import net.sourceforge.phpdt.internal.compiler.util.*; + +public class MethodDeclaration extends AbstractMethodDeclaration { + + public TypeReference returnType; + + /** + * MethodDeclaration constructor comment. + */ + public MethodDeclaration(CompilationResult compilationResult) { + super(compilationResult); + } + + + public void parseStatements(Parser parser, CompilationUnitDeclaration unit) { + + //fill up the method body with statement + if (ignoreFurtherInvestigation) + return; + parser.parse(this, unit); + } + + public void resolveStatements(ClassScope upperScope) { + + // ========= abort on fatal error ============= + if (this.returnType != null && this.binding != null) { + this.returnType.binding = this.binding.returnType; + // record the return type binding + } + // look if the name of the method is correct + if (binding != null && isTypeUseDeprecated(binding.returnType, scope)) + scope.problemReporter().deprecatedType(binding.returnType, returnType); + + if (CharOperation.equals(scope.enclosingSourceType().sourceName, selector)) + scope.problemReporter().methodWithConstructorName(this); + + // by grammatical construction, interface methods are always abstract + if (!scope.enclosingSourceType().isInterface()){ + + // if a method has an semicolon body and is not declared as abstract==>error + // native methods may have a semicolon body + if ((modifiers & AccSemicolonBody) != 0) { + if ((modifiers & AccNative) == 0) + if ((modifiers & AccAbstract) == 0) + scope.problemReporter().methodNeedingAbstractModifier(this); + } else { + // the method HAS a body --> abstract native modifiers are forbiden + if (((modifiers & AccNative) != 0) || ((modifiers & AccAbstract) != 0)) + scope.problemReporter().methodNeedingNoBody(this); + } + } + super.resolveStatements(upperScope); + } + + public String returnTypeToString(int tab) { + + if (returnType == null) + return ""; //$NON-NLS-1$ + return returnType.toString(tab) + " "; //$NON-NLS-1$ + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + ClassScope classScope) { + + if (visitor.visit(this, classScope)) { + if (returnType != null) + returnType.traverse(visitor, scope); + if (arguments != null) { + int argumentLength = arguments.length; + for (int i = 0; i < argumentLength; i++) + arguments[i].traverse(visitor, scope); + } + if (thrownExceptions != null) { + int thrownExceptionsLength = thrownExceptions.length; + for (int i = 0; i < thrownExceptionsLength; i++) + thrownExceptions[i].traverse(visitor, scope); + } + if (statements != null) { + int statementsLength = statements.length; + for (int i = 0; i < statementsLength; i++) + statements[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, classScope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/NameReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/NameReference.java new file mode 100644 index 0000000..2b5b79e --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/NameReference.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public abstract class NameReference extends Reference implements InvocationSite, BindingIds { + + public Binding binding, codegenBinding; //may be aTypeBinding-aFieldBinding-aLocalVariableBinding + + public TypeBinding receiverType, actualReceiverType; + + //the error printing + //some name reference are build as name reference but + //only used as type reference. When it happens, instead of + //creating a new objet (aTypeReference) we just flag a boolean + //This concesion is valuable while their are cases when the NameReference + //will be a TypeReference (static message sends.....) and there is + //no changeClass in java. +public NameReference() { + super(); + bits |= TYPE | VARIABLE; // restrictiveFlag + +} +public FieldBinding fieldBinding() { + //this method should be sent ONLY after a check against isFieldReference() + //check its use doing senders......... + + return (FieldBinding) binding ; +} +public boolean isSuperAccess() { + return false; +} +public boolean isTypeAccess() { + // null is acceptable when we are resolving the first part of a reference + return binding == null || binding instanceof ReferenceBinding; +} +public boolean isTypeReference() { + return binding instanceof ReferenceBinding; +} +public void setActualReceiverType(ReferenceBinding receiverType) { + this.actualReceiverType = receiverType; +} +public void setDepth(int depth) { + if (depth > 0) { + bits &= ~DepthMASK; // flush previous depth if any + bits |= (depth & 0xFF) << DepthSHIFT; // encoded on 8 bits + } +} +public void setFieldIndex(int index){ + // ignored +} + +public abstract String unboundReferenceErrorName(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/NullLiteral.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/NullLiteral.java new file mode 100644 index 0000000..3010590 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/NullLiteral.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class NullLiteral extends MagicLiteral { + static final char[] source = {'n' , 'u' , 'l' , 'l'}; +public NullLiteral(int s , int e) { + super(s,e); +} +public void computeConstant() { + + constant = Constant.fromValue(null);} +/** + * Code generation for the null literal + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + int pc = codeStream.position; + if (valueRequired) + codeStream.aconst_null(); + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public TypeBinding literalType(BlockScope scope) { + return NullBinding; +} +/** + * + */ +public char[] source() { + return source; +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/NumberLiteral.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/NumberLiteral.java new file mode 100644 index 0000000..f1b6ff4 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/NumberLiteral.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +public abstract class NumberLiteral extends Literal { + char[] source; +public NumberLiteral(char[] token, int s, int e) { + this(s,e) ; + source = token ; +} +public NumberLiteral(int s, int e) { + super (s,e) ; +} +public boolean isValidJavaStatement(){ + //should never be reach, but with a bug in the ast tree.... + //see comment on the Statement class + + return false ;} +public char[] source(){ + return source;} +public String toStringExpression(){ + + return new String(source);} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/OR_OR_Expression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/OR_OR_Expression.java new file mode 100644 index 0000000..f572772 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/OR_OR_Expression.java @@ -0,0 +1,296 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +//dedicated treatment for the || +public class OR_OR_Expression extends BinaryExpression { + + int rightInitStateIndex = -1; + int mergedInitStateIndex = -1; + + public OR_OR_Expression(Expression left, Expression right, int operator) { + super(left, right, operator); + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + Constant opConstant = left.conditionalConstant(); + if (opConstant != NotAConstant) { + if (opConstant.booleanValue() == false) { + // FALSE || anything + // need to be careful of scenario: + // (x || y) || !z, if passing the left info to the right, it would be swapped by the ! + FlowInfo mergedInfo = left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + mergedInfo = right.analyseCode(currentScope, flowContext, mergedInfo); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + } + FlowInfo leftInfo, rightInfo; + leftInfo = left.analyseCode(currentScope, flowContext, flowInfo); + + // need to be careful of scenario: + // (x || y) || !z, if passing the left info to the right, it would be swapped by the ! + rightInfo = leftInfo.initsWhenFalse().unconditionalInits().copy(); + if (opConstant != NotAConstant && opConstant.booleanValue() == true) rightInfo.markAsFakeReachable(true); + + rightInitStateIndex = + currentScope.methodScope().recordInitializationStates(rightInfo); + rightInfo = right.analyseCode(currentScope, flowContext, rightInfo); + FlowInfo mergedInfo = FlowInfo.conditional( + // merging two true initInfos for such a negative case: if ((t && (b = t)) || f) r = b; // b may not have been initialized + leftInfo.initsWhenTrue().copy().unconditionalInits().mergedWith( + rightInfo.initsWhenTrue().copy().unconditionalInits()), + rightInfo.initsWhenFalse().copy()); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + + /** + * Code generation for a binary operation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + int pc = codeStream.position; + Label falseLabel, endLabel; + if (constant != Constant.NotAConstant) { + if (valueRequired) + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + bits |= OnlyValueRequiredMASK; + generateOptimizedBoolean( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + valueRequired); + /* improving code gen for such a case: boolean b = i < 0 || true; + * since the label has never been used, we have the inlined value on the stack. */ + if (falseLabel.hasForwardReferences()) { + if (valueRequired) { + codeStream.iconst_1(); + if ((bits & ValueForReturnMASK) != 0) { + codeStream.ireturn(); + falseLabel.place(); + codeStream.iconst_0(); + } else { + codeStream.goto_(endLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + falseLabel.place(); + codeStream.iconst_0(); + endLabel.place(); + } + } else { + falseLabel.place(); + } + } + if (valueRequired) { + codeStream.generateImplicitConversion(implicitConversion); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + /** + * Boolean operator code generation + * Optimized operations are: || + */ + public void generateOptimizedBoolean( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) { + super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); + return; + } + int pc = codeStream.position; + Constant condConst; + if ((condConst = left.conditionalConstant()) != NotAConstant) { + if (condConst.booleanValue() == true) { + // || x + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if (valueRequired) { + if ((bits & OnlyValueRequiredMASK) != 0) { + codeStream.iconst_1(); + } else { + if (trueLabel != null) { + codeStream.goto_(trueLabel); + } + } + } + } else { + // || x + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if (rightInitStateIndex != -1) { + codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex); + } + if ((bits & OnlyValueRequiredMASK) != 0) { + right.generateCode(currentScope, codeStream, valueRequired); + } else { + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + } + return; + } + if ((condConst = right.conditionalConstant()) != NotAConstant) { + if (condConst.booleanValue() == true) { + // x || + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if (rightInitStateIndex != -1) { + codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex); + } + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if (valueRequired) { + if ((bits & OnlyValueRequiredMASK) != 0) { + codeStream.iconst_1(); + } else { + if (trueLabel != null) { + codeStream.goto_(trueLabel); + } + } + } + } else { + // x || + if ((bits & OnlyValueRequiredMASK) != 0) { + left.generateCode(currentScope, codeStream, valueRequired); + } else { + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + if (rightInitStateIndex != -1) { + codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex); + } + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + } + return; + } + // default case + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + left.generateOptimizedBoolean(currentScope, codeStream, trueLabel, null, true); + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + null, + valueRequired); + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + Label internalTrueLabel = new Label(codeStream); + left.generateOptimizedBoolean( + currentScope, + codeStream, + internalTrueLabel, + null, + true); + if (rightInitStateIndex != -1) { + codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex); + } + right.generateOptimizedBoolean( + currentScope, + codeStream, + null, + falseLabel, + valueRequired); + internalTrueLabel.place(); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + } + } + + public boolean isCompactableOperation() { + return false; + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + if (visitor.visit(this, scope)) { + left.traverse(visitor, scope); + right.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/OperatorExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/OperatorExpression.java new file mode 100644 index 0000000..6d9b7c5 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/OperatorExpression.java @@ -0,0 +1,1566 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; + +public abstract class OperatorExpression extends Expression implements OperatorIds { + + public static int[][] ResolveTypeTables = new int[NumberOfTables][]; + public TypeBinding typeBinding; + static {classInitialize();} + + /** + * OperatorExpression constructor comment. + */ + public OperatorExpression() { + super(); + } + public static final void classInitialize() { + ResolveTypeTables[AND] = get_AND(); + ResolveTypeTables[AND_AND] = get_AND_AND(); + ResolveTypeTables[DIVIDE] = get_DIVIDE(); + ResolveTypeTables[EQUAL_EQUAL] = get_EQUAL_EQUAL(); + ResolveTypeTables[GREATER] = get_GREATER(); + ResolveTypeTables[GREATER_EQUAL] = get_GREATER_EQUAL(); + ResolveTypeTables[LEFT_SHIFT] = get_LEFT_SHIFT(); + ResolveTypeTables[LESS] = get_LESS(); + ResolveTypeTables[LESS_EQUAL] = get_LESS_EQUAL(); + ResolveTypeTables[MINUS] = get_MINUS(); + ResolveTypeTables[MULTIPLY] = get_MULTIPLY(); + ResolveTypeTables[OR] = get_OR(); + ResolveTypeTables[OR_OR] = get_OR_OR(); + ResolveTypeTables[PLUS] = get_PLUS(); + ResolveTypeTables[REMAINDER] = get_REMAINDER(); + ResolveTypeTables[RIGHT_SHIFT] = get_RIGHT_SHIFT(); + ResolveTypeTables[UNSIGNED_RIGHT_SHIFT] = get_UNSIGNED_RIGHT_SHIFT(); + ResolveTypeTables[XOR] = get_XOR(); + } + + public static final String generateTableTestCase(){ + //return a String which is a java method allowing to test + //the non zero entries of all tables + + /* + org.eclipse.jdt.internal.compiler.ast. + OperatorExpression.generateTableTestCase(); + */ + + int[] operators = new int[]{AND,AND_AND,DIVIDE,GREATER,GREATER_EQUAL, + LEFT_SHIFT,LESS,LESS_EQUAL,MINUS,MULTIPLY,OR,OR_OR,PLUS,REMAINDER, + RIGHT_SHIFT,UNSIGNED_RIGHT_SHIFT,XOR}; + + class Decode { + public final String constant(int code){ + switch(code){ + case T_boolean : return "true" ; //$NON-NLS-1$ + case T_byte : return "((byte) 3)" ; //$NON-NLS-1$ + case T_char : return "'A'" ; //$NON-NLS-1$ + case T_double : return "300.0d" ; //$NON-NLS-1$ + case T_float : return "100.0f" ; //$NON-NLS-1$ + case T_int : return "1" ; //$NON-NLS-1$ + case T_long : return "7L" ; //$NON-NLS-1$ + case T_String : return "\"hello-world\"" ; //$NON-NLS-1$ + case T_null : return "null"; //$NON-NLS-1$ + case T_short : return "((short) 5)"; //$NON-NLS-1$ + case T_Object : return "null";} //$NON-NLS-1$ + return "";} //$NON-NLS-1$ + + public final String type(int code){ + switch(code){ + case T_boolean : return "z" ; //$NON-NLS-1$ + case T_byte : return "b" ; //$NON-NLS-1$ + case T_char : return "c" ; //$NON-NLS-1$ + case T_double : return "d" ; //$NON-NLS-1$ + case T_float : return "f" ; //$NON-NLS-1$ + case T_int : return "i" ; //$NON-NLS-1$ + case T_long : return "l" ; //$NON-NLS-1$ + case T_String : return "str" ; //$NON-NLS-1$ + case T_null : return "null"; //$NON-NLS-1$ + case T_short : return "s"; //$NON-NLS-1$ + case T_Object : return "obj";} //$NON-NLS-1$ + return "xxx";} //$NON-NLS-1$ + + public final String operator(int operator){ + switch (operator) { + case EQUAL_EQUAL : return "=="; //$NON-NLS-1$ + case LESS_EQUAL : return "<="; //$NON-NLS-1$ + case GREATER_EQUAL :return ">="; //$NON-NLS-1$ + case LEFT_SHIFT : return "<<"; //$NON-NLS-1$ + case RIGHT_SHIFT : return ">>"; //$NON-NLS-1$ + case UNSIGNED_RIGHT_SHIFT : return ">>>"; //$NON-NLS-1$ + case OR_OR :return "||"; //$NON-NLS-1$ + case AND_AND : return "&&"; //$NON-NLS-1$ + case PLUS : return "+"; //$NON-NLS-1$ + case MINUS : return "-"; //$NON-NLS-1$ + case NOT : return "!"; //$NON-NLS-1$ + case REMAINDER : return "%"; //$NON-NLS-1$ + case XOR : return "^"; //$NON-NLS-1$ + case AND : return "&"; //$NON-NLS-1$ + case MULTIPLY : return "*"; //$NON-NLS-1$ + case OR : return "|"; //$NON-NLS-1$ + case TWIDDLE : return "~"; //$NON-NLS-1$ + case DIVIDE : return "/"; //$NON-NLS-1$ + case GREATER : return ">"; //$NON-NLS-1$ + case LESS : return "<"; }; //$NON-NLS-1$ + return "????";} //$NON-NLS-1$ + } + + + Decode decode = new Decode(); + String s ; + + s = "\tpublic static void binaryOperationTablesTestCase(){\n" + //$NON-NLS-1$ + + "\t\t//TC test : all binary operation (described in tables)\n"+ //$NON-NLS-1$ + "\t\t//method automatically generated by\n"+ //$NON-NLS-1$ + "\t\t//org.eclipse.jdt.internal.compiler.ast.OperatorExpression.generateTableTestCase();\n"+ //$NON-NLS-1$ + + "\t\tString str0 ;\t String str\t= "+decode.constant(T_String)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\t\tint i0 ;\t int i\t= "+decode.constant(T_int)+" ;\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\t\tboolean z0;\t boolean z\t= "+decode.constant(T_boolean)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\t\tchar c0; \t char c\t= "+decode.constant(T_char)+" ;\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\t\tfloat f0; \t float f\t= "+decode.constant(T_float)+" ;\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\t\tdouble d0;\t double d\t= "+decode.constant(T_double)+" ;\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\t\tbyte b0; \t byte b\t= "+decode.constant(T_byte)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\t\tshort s0; \t short s\t= "+decode.constant(T_short)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\t\tlong l0; \t long l\t= "+decode.constant(T_long)+" ;\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\t\tObject obj0; \t Object obj\t= "+decode.constant(T_Object)+" ;\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\n"; //$NON-NLS-1$ + + int error = 0; + for (int i=0; i < operators.length ; i++) + { int operator = operators[i]; + for (int left=0; left<16;left++) + for (int right=0; right<16;right++) + { int result = (ResolveTypeTables[operator][(left<<4)+right]) & 0x0000F; + if (result != T_undefined) + + //1/ First regular computation then 2/ comparaison + //with a compile time constant (generated by the compiler) + // z0 = s >= s; + // if ( z0 != (((short) 5) >= ((short) 5))) + // System.out.println(155); + + { s += "\t\t"+decode.type(result)+"0"+" = "+decode.type(left); //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-2$ + s += " "+decode.operator(operator)+" "+decode.type(right)+";\n"; //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-3$ + String begin = result == T_String ? "\t\tif (! " : "\t\tif ( "; //$NON-NLS-2$ //$NON-NLS-1$ + String test = result == T_String ? ".equals(" : " != (" ; //$NON-NLS-2$ //$NON-NLS-1$ + s += begin +decode.type(result)+"0"+test //$NON-NLS-1$ + +decode.constant(left)+" " //$NON-NLS-1$ + +decode.operator(operator)+" " //$NON-NLS-1$ + +decode.constant(right)+"))\n"; //$NON-NLS-1$ + s += "\t\t\tSystem.out.println("+ (++error) +");\n"; //$NON-NLS-1$ //$NON-NLS-2$ + + } + } + } + + return s += "\n\t\tSystem.out.println(\"binary tables test : done\");}" ; //$NON-NLS-1$ + } + + public static final int[] get_AND(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + int[] table = new int[16*16] ; + + // table[(T_undefined<<4)+T_undefined] = T_undefined ; + // table[(T_undefined<<4)+T_byte] = T_undefined ; + // table[(T_undefined<<4)+T_long] = T_undefined ; + // table[(T_undefined<<4)+T_short] = T_undefined ; + // table[(T_undefined<<4)+T_void] = T_undefined ; + // table[(T_undefined<<4)+T_String] = T_undefined ; + // table[(T_undefined<<4)+T_Object] = T_undefined ; + // table[(T_undefined<<4)+T_double] = T_undefined ; + // table[(T_undefined<<4)+T_float] = T_undefined ; + // table[(T_undefined<<4)+T_boolean] = T_undefined ; + // table[(T_undefined<<4)+T_char] = T_undefined ; + // table[(T_undefined<<4)+T_int] = T_undefined ; + // table[(T_undefined<<4)+T_null] = T_undefined ; + + // table[(T_byte<<4)+T_undefined] = T_undefined ; + table[(T_byte<<4)+T_byte] = (Byte2Int<<12) +(Byte2Int<<4) +T_int ; + table[(T_byte<<4)+T_long] = (Byte2Long<<12)+(Long2Long<<4)+T_long ; + table[(T_byte<<4)+T_short] = (Byte2Int<<12) +(Short2Int<<4)+T_int; + // table[(T_byte<<4)+T_void] = T_undefined ; + // table[(T_byte<<4)+T_String] = T_undefined ; + // table[(T_byte<<4)+T_Object] = T_undefined ; + // table[(T_byte<<4)+T_double] = T_undefined ; + // table[(T_byte<<4)+T_float] = T_undefined ; + // table[(T_byte<<4)+T_boolean] = T_undefined ; + table[(T_byte<<4)+T_char] = (Byte2Int<<12) +(Char2Int<<4) +T_int ; + table[(T_byte<<4)+T_int] = (Byte2Int<<12) +(Int2Int<<4) +T_int ; + // table[(T_byte<<4)+T_null] = T_undefined ; + + // table[(T_long<<4)+T_undefined] = T_undefined ; + table[(T_long<<4)+T_byte] = (Long2Long<<12)+(Byte2Long<<4)+T_long; + table[(T_long<<4)+T_long] = (Long2Long<<12)+(Long2Long<<4)+T_long ; + table[(T_long<<4)+T_short] = (Long2Long<<12)+(Short2Long<<4)+T_long; ; + // table[(T_long<<4)+T_void] = T_undefined ; + // table[(T_long<<4)+T_String] = T_undefined ; + // table[(T_long<<4)+T_Object] = T_undefined ; + // table[(T_long<<4)+T_double] = T_undefined ; + // table[(T_long<<4)+T_float] = T_undefined ; + // table[(T_long<<4)+T_boolean] = T_undefined ; + table[(T_long<<4)+T_char] = (Long2Long<<12)+(Char2Long<<4)+T_long ; + table[(T_long<<4)+T_int] = (Long2Long<<12)+(Int2Long<<4)+T_long ; + // table[(T_long<<4)+T_null] = T_undefined ; + + // table[(T_short<<4)+T_undefined] = T_undefined ; + table[(T_short<<4)+T_byte] = (Short2Int<<12)+(Byte2Int<<4)+T_int ; + table[(T_short<<4)+T_long] = (Short2Long<<12)+(Long2Long<<4)+T_long ; + table[(T_short<<4)+T_short] = (Short2Int<<12)+(Short2Int<<4)+T_int ; + // table[(T_short<<4)+T_void] = T_undefined ; + // table[(T_short<<4)+T_String] = T_undefined ; + // table[(T_short<<4)+T_Object] = T_undefined ; + // table[(T_short<<4)+T_double] = T_undefined ; + // table[(T_short<<4)+T_float] = T_undefined ; + // table[(T_short<<4)+T_boolean] = T_undefined ; + table[(T_short<<4)+T_char] = (Short2Int<<12)+(Char2Int<<4)+T_int ; + table[(T_short<<4)+T_int] = (Short2Int<<12)+(Int2Int<<4)+T_int ; + // table[(T_short<<4)+T_null] = T_undefined ; + + // table[(T_void<<4)+T_undefined] = T_undefined ; + // table[(T_void<<4)+T_byte] = T_undefined ; + // table[(T_void<<4)+T_long] = T_undefined ; + // table[(T_void<<4)+T_short] = T_undefined ; + // table[(T_void<<4)+T_void] = T_undefined ; + // table[(T_void<<4)+T_String] = T_undefined ; + // table[(T_void<<4)+T_Object] = T_undefined ; + // table[(T_void<<4)+T_double] = T_undefined ; + // table[(T_void<<4)+T_float] = T_undefined ; + // table[(T_void<<4)+T_boolean] = T_undefined ; + // table[(T_void<<4)+T_char] = T_undefined ; + // table[(T_void<<4)+T_int] = T_undefined ; + // table[(T_void<<4)+T_null] = T_undefined ; + + // table[(T_String<<4)+T_undefined] = T_undefined ; + // table[(T_String<<4)+T_byte] = T_undefined ; + // table[(T_String<<4)+T_long] = T_undefined ; + // table[(T_String<<4)+T_short] = T_undefined ; + // table[(T_String<<4)+T_void] = T_undefined ; + // table[(T_String<<4)+T_String] = T_undefined ; + // table[(T_String<<4)+T_Object] = T_undefined ; + // table[(T_String<<4)+T_double] = T_undefined ; + // table[(T_String<<4)+T_float] = T_undefined ; + // table[(T_String<<4)+T_boolean] = T_undefined ; + // table[(T_String<<4)+T_char] = T_undefined ; + // table[(T_String<<4)+T_int] = T_undefined ; + // table[(T_String<<4)+T_null] = T_undefined ; + + // table[(T_Object<<4)+T_undefined] = T_undefined ; + // table[(T_Object<<4)+T_byte] = T_undefined ; + // table[(T_Object<<4)+T_long] = T_undefined ; + // table[(T_Object<<4)+T_short] = T_undefined ; + // table[(T_Object<<4)+T_void] = T_undefined ; + // table[(T_Object<<4)+T_String] = T_undefined ; + // table[(T_Object<<4)+T_Object] = T_undefined ; + // table[(T_Object<<4)+T_double] = T_undefined ; + // table[(T_Object<<4)+T_float] = T_undefined ; + // table[(T_Object<<4)+T_boolean] = T_undefined ; + // table[(T_Object<<4)+T_char] = T_undefined ; + // table[(T_Object<<4)+T_int] = T_undefined ; + // table[(T_Object<<4)+T_null] = T_undefined ; + + // table[(T_double<<4)+T_undefined] = T_undefined ; + // table[(T_double<<4)+T_byte] = T_undefined ; + // table[(T_double<<4)+T_long] = T_undefined ; + // table[(T_double<<4)+T_short] = T_undefined ; + // table[(T_double<<4)+T_void] = T_undefined ; + // table[(T_double<<4)+T_String] = T_undefined ; + // table[(T_double<<4)+T_Object] = T_undefined ; + // table[(T_double<<4)+T_double] = T_undefined ; + // table[(T_double<<4)+T_float] = T_undefined ; + // table[(T_double<<4)+T_boolean] = T_undefined ; + // table[(T_double<<4)+T_char] = T_undefined ; + // table[(T_double<<4)+T_int] = T_undefined; + // table[(T_double<<4)+T_null] = T_undefined ; + + // table[(T_float<<4)+T_undefined] = T_undefined ; + // table[(T_float<<4)+T_byte] = T_undefined ; + // table[(T_float<<4)+T_long] = T_undefined ; + // table[(T_float<<4)+T_short] = T_undefined ; + // table[(T_float<<4)+T_void] = T_undefined ; + // table[(T_float<<4)+T_String] = T_undefined ; + // table[(T_float<<4)+T_Object] = T_undefined ; + // table[(T_float<<4)+T_double] = T_undefined ; + // table[(T_float<<4)+T_float] = T_undefined ; + // table[(T_float<<4)+T_boolean] = T_undefined ; + // table[(T_float<<4)+T_char] = T_undefined ; + // table[(T_float<<4)+T_int] = T_undefined ; + // table[(T_float<<4)+T_null] = T_undefined ; + + // table[(T_boolean<<4)+T_undefined] = T_undefined ; + // table[(T_boolean<<4)+T_byte] = T_undefined ; + // table[(T_boolean<<4)+T_long] = T_undefined ; + // table[(T_boolean<<4)+T_short] = T_undefined ; + // table[(T_boolean<<4)+T_void] = T_undefined ; + // table[(T_boolean<<4)+T_String] = T_undefined ; + // table[(T_boolean<<4)+T_Object] = T_undefined ; + // table[(T_boolean<<4)+T_double] = T_undefined ; + // table[(T_boolean<<4)+T_float] = T_undefined ; + table[(T_boolean<<4)+T_boolean] = (Boolean2Boolean << 12)+(Boolean2Boolean << 4)+T_boolean ; + // table[(T_boolean<<4)+T_char] = T_undefined ; + // table[(T_boolean<<4)+T_int] = T_undefined ; + // table[(T_boolean<<4)+T_null] = T_undefined ; + + // table[(T_char<<4)+T_undefined] = T_undefined ; + table[(T_char<<4)+T_byte] = (Char2Int<<12)+(Byte2Int<<4)+T_int ; + table[(T_char<<4)+T_long] = (Char2Long<<12)+(Long2Long<<4)+T_long; + table[(T_char<<4)+T_short] = (Char2Int<<12)+(Short2Int<<4)+T_int ; + // table[(T_char<<4)+T_void] = T_undefined ; + // table[(T_char<<4)+T_String] = T_undefined ; + // table[(T_char<<4)+T_Object] = T_undefined ; + // table[(T_char<<4)+T_double] = T_undefined ; + // table[(T_char<<4)+T_float] = T_undefined ; + // table[(T_char<<4)+T_boolean] = T_undefined ; + table[(T_char<<4)+T_char] = (Char2Int<<12)+(Char2Int<<4)+T_int ; + table[(T_char<<4)+T_int] = (Char2Int<<12)+(Int2Int<<4)+T_int ; + // table[(T_char<<4)+T_null] = T_undefined ; + + // table[(T_int<<4)+T_undefined] = T_undefined ; + table[(T_int<<4)+T_byte] = (Int2Int<<12)+(Byte2Int<<4)+T_int ; + table[(T_int<<4)+T_long] = (Int2Long<<12)+(Long2Long<<4)+T_long ; + table[(T_int<<4)+T_short] = (Int2Int<<12)+(Short2Int<<4)+T_int ; + // table[(T_int<<4)+T_void] = T_undefined ; + // table[(T_int<<4)+T_String] = T_undefined ; + // table[(T_int<<4)+T_Object] = T_undefined ; + // table[(T_int<<4)+T_double] = T_undefined ; + // table[(T_int<<4)+T_float] = T_undefined ; + // table[(T_int<<4)+T_boolean] = T_undefined ; + table[(T_int<<4)+T_char] = (Int2Int<<12)+(Char2Int<<4)+T_int ; + table[(T_int<<4)+T_int] = (Int2Int<<12)+(Int2Int<<4)+T_int ; + // table[(T_int<<4)+T_null] = T_undefined ; + + // table[(T_null<<4)+T_undefined] = T_undefined ; + // table[(T_null<<4)+T_byte] = T_undefined ; + // table[(T_null<<4)+T_long] = T_undefined ; + // table[(T_null<<4)+T_short] = T_undefined ; + // table[(T_null<<4)+T_void] = T_undefined ; + // table[(T_null<<4)+T_String] = T_undefined ; + // table[(T_null<<4)+T_Object] = T_undefined ; + // table[(T_null<<4)+T_double] = T_undefined ; + // table[(T_null<<4)+T_float] = T_undefined ; + // table[(T_null<<4)+T_boolean] = T_undefined ; + // table[(T_null<<4)+T_char] = T_undefined ; + // table[(T_null<<4)+T_int] = T_undefined ; + // table[(T_null<<4)+T_null] = T_undefined ; + + return table ; + } + + public static final int[] get_AND_AND(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + int[] table = new int[16*16] ; + + // table[(T_undefined<<4)+T_undefined] = T_undefined ; + // table[(T_undefined<<4)+T_byte] = T_undefined ; + // table[(T_undefined<<4)+T_long] = T_undefined ; + // table[(T_undefined<<4)+T_short] = T_undefined ; + // table[(T_undefined<<4)+T_void] = T_undefined ; + // table[(T_undefined<<4)+T_String] = T_undefined ; + // table[(T_undefined<<4)+T_Object] = T_undefined ; + // table[(T_undefined<<4)+T_double] = T_undefined ; + // table[(T_undefined<<4)+T_float] = T_undefined ; + // table[(T_undefined<<4)+T_boolean] = T_undefined ; + // table[(T_undefined<<4)+T_char] = T_undefined ; + // table[(T_undefined<<4)+T_int] = T_undefined ; + // table[(T_undefined<<4)+T_null] = T_undefined ; + + // table[(T_byte<<4)+T_undefined] = T_undefined ; + // table[(T_byte<<4)+T_byte] = T_undefined ; + // table[(T_byte<<4)+T_long] = T_undefined ; + // table[(T_byte<<4)+T_short] = T_undefined ; + // table[(T_byte<<4)+T_void] = T_undefined ; + // table[(T_byte<<4)+T_String] = T_undefined ; + // table[(T_byte<<4)+T_Object] = T_undefined ; + // table[(T_byte<<4)+T_double] = T_undefined ; + // table[(T_byte<<4)+T_float] = T_undefined ; + // table[(T_byte<<4)+T_boolean] = T_undefined ; + // table[(T_byte<<4)+T_char] = T_undefined ; + // table[(T_byte<<4)+T_int] = T_undefined ; + // table[(T_byte<<4)+T_null] = T_undefined ; + + // table[(T_long<<4)+T_undefined] = T_undefined ; + // table[(T_long<<4)+T_byte] = T_undefined; + // table[(T_long<<4)+T_long] = T_undefined ; + // table[(T_long<<4)+T_short] = T_undefined ; + // table[(T_long<<4)+T_void] = T_undefined ; + // table[(T_long<<4)+T_String] = T_undefined ; + // table[(T_long<<4)+T_Object] = T_undefined ; + // table[(T_long<<4)+T_double] = T_undefined ; + // table[(T_long<<4)+T_float] = T_undefined ; + // table[(T_long<<4)+T_boolean] = T_undefined ; + // table[(T_long<<4)+T_char] = T_undefined ; + // table[(T_long<<4)+T_int] = T_undefined ; + // table[(T_long<<4)+T_null] = T_undefined ; + + // table[(T_short<<4)+T_undefined] = T_undefined ; + // table[(T_short<<4)+T_byte] = T_undefined ; + // table[(T_short<<4)+T_long] = T_undefined ; + // table[(T_short<<4)+T_short] = T_undefined ; + // table[(T_short<<4)+T_void] = T_undefined ; + // table[(T_short<<4)+T_String] = T_undefined ; + // table[(T_short<<4)+T_Object] = T_undefined ; + // table[(T_short<<4)+T_double] = T_undefined ; + // table[(T_short<<4)+T_float] = T_undefined ; + // table[(T_short<<4)+T_boolean] = T_undefined ; + // table[(T_short<<4)+T_char] = T_undefined ; + // table[(T_short<<4)+T_int] = T_undefined ; + // table[(T_short<<4)+T_null] = T_undefined ; + + // table[(T_void<<4)+T_undefined] = T_undefined ; + // table[(T_void<<4)+T_byte] = T_undefined ; + // table[(T_void<<4)+T_long] = T_undefined ; + // table[(T_void<<4)+T_short] = T_undefined ; + // table[(T_void<<4)+T_void] = T_undefined ; + // table[(T_void<<4)+T_String] = T_undefined ; + // table[(T_void<<4)+T_Object] = T_undefined ; + // table[(T_void<<4)+T_double] = T_undefined ; + // table[(T_void<<4)+T_float] = T_undefined ; + // table[(T_void<<4)+T_boolean] = T_undefined ; + // table[(T_void<<4)+T_char] = T_undefined ; + // table[(T_void<<4)+T_int] = T_undefined ; + // table[(T_void<<4)+T_null] = T_undefined ; + + // table[(T_String<<4)+T_undefined] = T_undefined ; + // table[(T_String<<4)+T_byte] = T_undefined ; + // table[(T_String<<4)+T_long] = T_undefined ; + // table[(T_String<<4)+T_short] = T_undefined ; + // table[(T_String<<4)+T_void] = T_undefined ; + // table[(T_String<<4)+T_String] = T_undefined ; + // table[(T_String<<4)+T_Object] = T_undefined ; + // table[(T_String<<4)+T_double] = T_undefined ; + // table[(T_String<<4)+T_float] = T_undefined ; + // table[(T_String<<4)+T_boolean] = T_undefined ; + // table[(T_String<<4)+T_char] = T_undefined ; + // table[(T_String<<4)+T_int] = T_undefined ; + // table[(T_String<<4)+T_null] = T_undefined ; + + // table[(T_Object<<4)+T_undefined] = T_undefined ; + // table[(T_Object<<4)+T_byte] = T_undefined ; + // table[(T_Object<<4)+T_long] = T_undefined ; + // table[(T_Object<<4)+T_short] = T_undefined ; + // table[(T_Object<<4)+T_void] = T_undefined ; + // table[(T_Object<<4)+T_String] = T_undefined ; + // table[(T_Object<<4)+T_Object] = T_undefined ; + // table[(T_Object<<4)+T_double] = T_undefined ; + // table[(T_Object<<4)+T_float] = T_undefined ; + // table[(T_Object<<4)+T_boolean] = T_undefined ; + // table[(T_Object<<4)+T_char] = T_undefined ; + // table[(T_Object<<4)+T_int] = T_undefined ; + // table[(T_Object<<4)+T_null] = T_undefined ; + + // table[(T_double<<4)+T_undefined] = T_undefined ; + // table[(T_double<<4)+T_byte] = T_undefined ; + // table[(T_double<<4)+T_long] = T_undefined ; + // table[(T_double<<4)+T_short] = T_undefined ; + // table[(T_double<<4)+T_void] = T_undefined ; + // table[(T_double<<4)+T_String] = T_undefined ; + // table[(T_double<<4)+T_Object] = T_undefined ; + // table[(T_double<<4)+T_double] = T_undefined ; + // table[(T_double<<4)+T_float] = T_undefined ; + // table[(T_double<<4)+T_boolean] = T_undefined ; + // table[(T_double<<4)+T_char] = T_undefined ; + // table[(T_double<<4)+T_int] = T_undefined; + // table[(T_double<<4)+T_null] = T_undefined ; + + // table[(T_float<<4)+T_undefined] = T_undefined ; + // table[(T_float<<4)+T_byte] = T_undefined ; + // table[(T_float<<4)+T_long] = T_undefined ; + // table[(T_float<<4)+T_short] = T_undefined ; + // table[(T_float<<4)+T_void] = T_undefined ; + // table[(T_float<<4)+T_String] = T_undefined ; + // table[(T_float<<4)+T_Object] = T_undefined ; + // table[(T_float<<4)+T_double] = T_undefined ; + // table[(T_float<<4)+T_float] = T_undefined ; + // table[(T_float<<4)+T_boolean] = T_undefined ; + // table[(T_float<<4)+T_char] = T_undefined ; + // table[(T_float<<4)+T_int] = T_undefined ; + // table[(T_float<<4)+T_null] = T_undefined ; + + // table[(T_boolean<<4)+T_undefined] = T_undefined ; + // table[(T_boolean<<4)+T_byte] = T_undefined ; + // table[(T_boolean<<4)+T_long] = T_undefined ; + // table[(T_boolean<<4)+T_short] = T_undefined ; + // table[(T_boolean<<4)+T_void] = T_undefined ; + // table[(T_boolean<<4)+T_String] = T_undefined ; + // table[(T_boolean<<4)+T_Object] = T_undefined ; + // table[(T_boolean<<4)+T_double] = T_undefined ; + // table[(T_boolean<<4)+T_float] = T_undefined ; + table[(T_boolean<<4)+T_boolean] = (Boolean2Boolean<<12)+(Boolean2Boolean<<4)+T_boolean ; + // table[(T_boolean<<4)+T_char] = T_undefined ; + // table[(T_boolean<<4)+T_int] = T_undefined ; + // table[(T_boolean<<4)+T_null] = T_undefined ; + + // table[(T_char<<4)+T_undefined] = T_undefined ; + // table[(T_char<<4)+T_byte] = T_undefined ; + // table[(T_char<<4)+T_long] = T_undefined; + // table[(T_char<<4)+T_short] = T_undefined ; + // table[(T_char<<4)+T_void] = T_undefined ; + // table[(T_char<<4)+T_String] = T_undefined ; + // table[(T_char<<4)+T_Object] = T_undefined ; + // table[(T_char<<4)+T_double] = T_undefined ; + // table[(T_char<<4)+T_float] = T_undefined ; + // table[(T_char<<4)+T_boolean] = T_undefined ; + // table[(T_char<<4)+T_char] = T_undefined ; + // table[(T_char<<4)+T_int] = T_undefined ; + // table[(T_char<<4)+T_null] = T_undefined ; + + // table[(T_int<<4)+T_undefined] = T_undefined ; + // table[(T_int<<4)+T_byte] = T_undefined ; + // table[(T_int<<4)+T_long] = T_undefined ; + // table[(T_int<<4)+T_short] = T_undefined ; + // table[(T_int<<4)+T_void] = T_undefined ; + // table[(T_int<<4)+T_String] = T_undefined ; + // table[(T_int<<4)+T_Object] = T_undefined ; + // table[(T_int<<4)+T_double] = T_undefined ; + // table[(T_int<<4)+T_float] = T_undefined ; + // table[(T_int<<4)+T_boolean] = T_undefined ; + // table[(T_int<<4)+T_char] = T_undefined ; + // table[(T_int<<4)+T_int] = T_undefined ; + // table[(T_int<<4)+T_null] = T_undefined ; + + // table[(T_null<<4)+T_undefined] = T_undefined ; + // table[(T_null<<4)+T_byte] = T_undefined ; + // table[(T_null<<4)+T_long] = T_undefined ; + // table[(T_null<<4)+T_short] = T_undefined ; + // table[(T_null<<4)+T_void] = T_undefined ; + // table[(T_null<<4)+T_String] = T_undefined ; + // table[(T_null<<4)+T_Object] = T_undefined ; + // table[(T_null<<4)+T_double] = T_undefined ; + // table[(T_null<<4)+T_float] = T_undefined ; + // table[(T_null<<4)+T_boolean] = T_undefined ; + // table[(T_null<<4)+T_char] = T_undefined ; + // table[(T_null<<4)+T_int] = T_undefined ; + // table[(T_null<<4)+T_null] = T_undefined ; + return table ; + } + + public static final int[] get_DIVIDE(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + + // int[] table = new int[16*16] ; + + return get_MINUS(); + } + + public static final int[] get_EQUAL_EQUAL(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + int[] table = new int[16*16] ; + + // table[(T_undefined<<4)+T_undefined] = T_undefined ; + // table[(T_undefined<<4)+T_byte] = T_undefined ; + // table[(T_undefined<<4)+T_long] = T_undefined ; + // table[(T_undefined<<4)+T_short] = T_undefined ; + // table[(T_undefined<<4)+T_void] = T_undefined ; + // table[(T_undefined<<4)+T_String] = T_undefined ; + // table[(T_undefined<<4)+T_Object] = T_undefined ; + // table[(T_undefined<<4)+T_double] = T_undefined ; + // table[(T_undefined<<4)+T_float] = T_undefined ; + // table[(T_undefined<<4)+T_boolean] = T_undefined ; + // table[(T_undefined<<4)+T_char] = T_undefined ; + // table[(T_undefined<<4)+T_int] = T_undefined ; + // table[(T_undefined<<4)+T_null] = T_undefined ; + + // table[(T_byte<<4)+T_undefined] = T_undefined ; + table[(T_byte<<4)+T_byte] = (Byte2Int<<12)+(Byte2Int<<4)+T_boolean ; + table[(T_byte<<4)+T_long] = (Byte2Long<<12)+(Long2Long<<4)+T_boolean ; + table[(T_byte<<4)+T_short] = (Byte2Int<<12)+(Short2Int<<4)+T_boolean ; + // table[(T_byte<<4)+T_void] = T_undefined ; + // table[(T_byte<<4)+T_String] = T_undefined ; + // table[(T_byte<<4)+T_Object] = T_undefined ; + table[(T_byte<<4)+T_double] = (Byte2Double<<12)+(Double2Double<<4)+T_boolean ; + table[(T_byte<<4)+T_float] = (Byte2Float<<12)+(Float2Float<<4)+T_boolean; + // table[(T_byte<<4)+T_boolean] = T_undefined ; + table[(T_byte<<4)+T_char] = (Byte2Int<<12)+(Char2Int<<4)+T_boolean ; + table[(T_byte<<4)+T_int] = (Byte2Int<<12)+(Int2Int<<4)+T_boolean; + // table[(T_byte<<4)+T_null] = T_undefined ; + + // table[(T_long<<4)+T_undefined] = T_undefined ; + table[(T_long<<4)+T_byte] = (Long2Long<<12)+(Byte2Long<<4)+T_boolean; + table[(T_long<<4)+T_long] = (Long2Long<<12)+(Long2Long<<4)+T_boolean ; + table[(T_long<<4)+T_short] = (Long2Long<<12)+(Short2Long<<4)+T_boolean ; + // table[(T_long<<4)+T_void] = T_undefined ; + // table[(T_long<<4)+T_String] = T_undefined ; + // table[(T_long<<4)+T_Object] = T_undefined ; + table[(T_long<<4)+T_double] = (Long2Double<<12)+(Double2Double<<4)+T_boolean ; + table[(T_long<<4)+T_float] = (Long2Float<<12)+(Float2Float<<4)+T_boolean ; + // table[(T_long<<4)+T_boolean] = T_undefined ; + table[(T_long<<4)+T_char] = (Long2Long<<12)+(Char2Long<<4)+T_boolean ; + table[(T_long<<4)+T_int] = (Long2Long<<12)+(Int2Long<<4)+T_boolean ; + // table[(T_long<<4)+T_null] = T_undefined ; + + // table[(T_short<<4)+T_undefined] = T_undefined ; + table[(T_short<<4)+T_byte] = (Short2Int<<12)+(Byte2Int<<4)+T_boolean ; + table[(T_short<<4)+T_long] = (Short2Long<<12)+(Long2Long<<4)+T_boolean ; + table[(T_short<<4)+T_short] = (Short2Int<<12)+(Short2Int<<4)+T_boolean ; + // table[(T_short<<4)+T_void] = T_undefined ; + // table[(T_short<<4)+T_String] = T_undefined ; + // table[(T_short<<4)+T_Object] = T_undefined ; + table[(T_short<<4)+T_double] = (Short2Double<<12)+(Double2Double<<4)+T_boolean ; + table[(T_short<<4)+T_float] = (Short2Float<<12)+(Float2Float<<4)+T_boolean ; + // table[(T_short<<4)+T_boolean] = T_undefined ; + table[(T_short<<4)+T_char] = (Short2Int<<12)+(Char2Int<<4)+T_boolean ; + table[(T_short<<4)+T_int] = (Short2Int<<12)+(Int2Int<<4)+T_boolean ; + // table[(T_short<<4)+T_null] = T_undefined ; + + // table[(T_void<<4)+T_undefined] = T_undefined ; + // table[(T_void<<4)+T_byte] = T_undefined ; + // table[(T_void<<4)+T_long] = T_undefined ; + // table[(T_void<<4)+T_short] = T_undefined ; + // table[(T_void<<4)+T_void] = T_undefined ; + // table[(T_void<<4)+T_String] = T_undefined ; + // table[(T_void<<4)+T_Object] = T_undefined ; + // table[(T_void<<4)+T_double] = T_undefined ; + // table[(T_void<<4)+T_float] = T_undefined ; + // table[(T_void<<4)+T_boolean] = T_undefined ; + // table[(T_void<<4)+T_char] = T_undefined ; + // table[(T_void<<4)+T_int] = T_undefined ; + // table[(T_void<<4)+T_null] = T_undefined ; + + // table[(T_String<<4)+T_undefined] = T_undefined ; + // table[(T_String<<4)+T_byte] = T_undefined ; + // table[(T_String<<4)+T_long] = T_undefined ; + // table[(T_String<<4)+T_short] = T_undefined ; + // table[(T_String<<4)+T_void] = T_undefined ; + table[(T_String<<4)+T_String] = /*String2Object String2Object*/ + (T_Object<<16)+(T_String<<12)+(T_Object<<8)+(T_String<<4)+T_boolean ; + table[(T_String<<4)+T_Object] = /*String2Object Object2Object*/ + (T_Object<<16)+(T_String<<12)+(T_Object<<8)+(T_Object<<4)+T_boolean ; + // table[(T_String<<4)+T_double] = T_undefined ; + // table[(T_String<<4)+T_float] = T_undefined ; + // table[(T_String<<4)+T_boolean] = T_undefined ; + // table[(T_String<<4)+T_char] = T_undefined ; + // table[(T_String<<4)+T_int] = T_undefined ; + table[(T_String<<4)+T_null] = /*Object2String null2Object */ + (T_Object<<16)+(T_String<<12)+(T_Object<<8)+(T_null<<4)+T_boolean ; + + // table[(T_Object<<4)+T_undefined] = T_undefined ; + // table[(T_Object<<4)+T_byte] = T_undefined ; + // table[(T_Object<<4)+T_long] = T_undefined ; + // table[(T_Object<<4)+T_short] = T_undefined ; + // table[(T_Object<<4)+T_void] = T_undefined ; + table[(T_Object<<4)+T_String] = /*Object2Object String2Object*/ + (T_Object<<16)+(T_Object<<12)+(T_Object<<8)+(T_String<<4)+T_boolean ; + table[(T_Object<<4)+T_Object] = /*Object2Object Object2Object*/ + (T_Object<<16)+(T_Object<<12)+(T_Object<<8)+(T_Object<<4)+T_boolean ; + // table[(T_Object<<4)+T_double] = T_undefined ; + // table[(T_Object<<4)+T_float] = T_undefined ; + // table[(T_Object<<4)+T_boolean] = T_undefined ; + // table[(T_Object<<4)+T_char] = T_undefined ; + // table[(T_Object<<4)+T_int] = T_undefined ; + table[(T_Object<<4)+T_null] = /*Object2Object null2Object*/ + (T_Object<<16)+(T_Object<<12)+(T_Object<<8)+(T_null<<4)+T_boolean ; + + // table[(T_double<<4)+T_undefined] = T_undefined ; + table[(T_double<<4)+T_byte] = (Double2Double<<12)+(Byte2Double<<4)+T_boolean ; + table[(T_double<<4)+T_long] = (Double2Double<<12)+(Long2Double<<4)+T_boolean ; + table[(T_double<<4)+T_short] = (Double2Double<<12)+(Short2Double<<4)+T_boolean ; + // table[(T_double<<4)+T_void] = T_undefined ; + // table[(T_double<<4)+T_String] = T_undefined ; + // table[(T_double<<4)+T_Object] = T_undefined ; + table[(T_double<<4)+T_double] = (Double2Double<<12)+(Double2Double<<4)+T_boolean ; + table[(T_double<<4)+T_float] = (Double2Double<<12)+(Float2Double<<4)+T_boolean; + // table[(T_double<<4)+T_boolean] = T_undefined ; + table[(T_double<<4)+T_char] = (Double2Double<<12)+(Char2Double<<4)+T_boolean ; + table[(T_double<<4)+T_int] = (Double2Double<<12)+(Int2Double<<4)+T_boolean ; + // table[(T_double<<4)+T_null] = T_undefined ; + + // table[(T_float<<4)+T_undefined] = T_undefined ; + table[(T_float<<4)+T_byte] = (Float2Float<<12)+(Byte2Float<<4)+T_boolean ; + table[(T_float<<4)+T_long] = (Float2Float<<12)+(Long2Float<<4)+T_boolean ; + table[(T_float<<4)+T_short] = (Float2Float<<12)+(Short2Float<<4)+T_boolean ; + // table[(T_float<<4)+T_void] = T_undefined ; + // table[(T_float<<4)+T_String] = T_undefined ; + // table[(T_float<<4)+T_Object] = T_undefined ; + table[(T_float<<4)+T_double] = (Float2Double<<12)+(Double2Double<<4)+T_boolean ; + table[(T_float<<4)+T_float] = (Float2Float<<12)+(Float2Float<<4)+T_boolean ; + // table[(T_float<<4)+T_boolean] = T_undefined ; + table[(T_float<<4)+T_char] = (Float2Float<<12)+(Char2Float<<4)+T_boolean ; + table[(T_float<<4)+T_int] = (Float2Float<<12)+(Int2Float<<4)+T_boolean ; + // table[(T_float<<4)+T_null] = T_undefined ; + + // table[(T_boolean<<4)+T_undefined] = T_undefined ; + // table[(T_boolean<<4)+T_byte] = T_undefined ; + // table[(T_boolean<<4)+T_long] = T_undefined ; + // table[(T_boolean<<4)+T_short] = T_undefined ; + // table[(T_boolean<<4)+T_void] = T_undefined ; + // table[(T_boolean<<4)+T_String] = T_undefined ; + // table[(T_boolean<<4)+T_Object] = T_undefined ; + // table[(T_boolean<<4)+T_double] = T_undefined ; + // table[(T_boolean<<4)+T_float] = T_undefined ; + table[(T_boolean<<4)+T_boolean] = (Boolean2Boolean<<12)+(Boolean2Boolean<<4)+T_boolean ; + // table[(T_boolean<<4)+T_char] = T_undefined ; + // table[(T_boolean<<4)+T_int] = T_undefined ; + // table[(T_boolean<<4)+T_null] = T_undefined ; + + // table[(T_char<<4)+T_undefined] = T_undefined ; + table[(T_char<<4)+T_byte] = (Char2Int<<12)+(Byte2Int<<4)+T_boolean ; + table[(T_char<<4)+T_long] = (Char2Long<<12)+(Long2Long<<4)+T_boolean ; + table[(T_char<<4)+T_short] = (Char2Int<<12)+(Short2Int<<4)+T_boolean ; + // table[(T_char<<4)+T_void] = T_undefined ; + // table[(T_char<<4)+T_String] = T_undefined ; + // table[(T_char<<4)+T_Object] = T_undefined ; + table[(T_char<<4)+T_double] = (Char2Double<<12)+(Double2Double<<4)+T_boolean ; + table[(T_char<<4)+T_float] = (Char2Float<<12)+(Float2Float<<4)+T_boolean ; + // table[(T_char<<4)+T_boolean] = T_undefined ; + table[(T_char<<4)+T_char] = (Char2Int<<12)+(Char2Int<<4)+T_boolean ; + table[(T_char<<4)+T_int] = (Char2Int<<12)+(Int2Int<<4)+T_boolean ; + // table[(T_char<<4)+T_null] = T_undefined ; + + // table[(T_int<<4)+T_undefined] = T_undefined ; + table[(T_int<<4)+T_byte] = (Int2Int<<12)+(Byte2Int<<4)+T_boolean ; + table[(T_int<<4)+T_long] = (Int2Long<<12)+(Long2Long<<4)+T_boolean ; + table[(T_int<<4)+T_short] = (Int2Int<<12)+(Short2Int<<4)+T_boolean ; + // table[(T_int<<4)+T_void] = T_undefined ; + // table[(T_int<<4)+T_String] = T_undefined ; + // table[(T_int<<4)+T_Object] = T_undefined ; + table[(T_int<<4)+T_double] = (Int2Double<<12)+(Double2Double<<4)+T_boolean ; + table[(T_int<<4)+T_float] = (Int2Float<<12)+(Float2Float<<4)+T_boolean; + // table[(T_int<<4)+T_boolean] = T_undefined ; + table[(T_int<<4)+T_char] = (Int2Int<<12)+(Char2Int<<4)+T_boolean ; + table[(T_int<<4)+T_int] = (Int2Int<<12)+(Int2Int<<4)+T_boolean ; + // table[(T_int<<4)+T_null] = T_undefined ; + + // table[(T_null<<4)+T_undefined] = T_undefined ; + // table[(T_null<<4)+T_byte] = T_undefined ; + // table[(T_null<<4)+T_long] = T_undefined ; + // table[(T_null<<4)+T_short] = T_undefined ; + // table[(T_null<<4)+T_void] = T_undefined ; + table[(T_null<<4)+T_String] = /*null2Object String2Object*/ + (T_Object<<16)+(T_null<<12)+(T_Object<<8)+(T_String<<4)+T_boolean ; + table[(T_null<<4)+T_Object] = /*null2Object Object2Object*/ + (T_Object<<16)+(T_null<<12)+(T_Object<<8)+(T_Object<<4)+T_boolean ; ; + // table[(T_null<<4)+T_double] = T_undefined ; + // table[(T_null<<4)+T_float] = T_undefined ; + // table[(T_null<<4)+T_boolean] = T_undefined ; + // table[(T_null<<4)+T_char] = T_undefined ; + // table[(T_null<<4)+T_int] = T_undefined ; + table[(T_null<<4)+T_null] = /*null2Object null2Object*/ + (T_Object<<16)+(T_null<<12)+(T_Object<<8)+(T_null<<4)+T_boolean ; + return table ; + } + + public static final int[] get_GREATER(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + // int[] table = new int[16*16] ; + return get_LESS(); + } + + public static final int[] get_GREATER_EQUAL(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + // int[] table = new int[16*16] ; + return get_LESS(); + } + + public static final int[] get_LEFT_SHIFT(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + int[] table = new int[16*16] ; + + // table[(T_undefined<<4)+T_undefined] = T_undefined ; + // table[(T_undefined<<4)+T_byte] = T_undefined ; + // table[(T_undefined<<4)+T_long] = T_undefined ; + // table[(T_undefined<<4)+T_short] = T_undefined ; + // table[(T_undefined<<4)+T_void] = T_undefined ; + // table[(T_undefined<<4)+T_String] = T_undefined ; + // table[(T_undefined<<4)+T_Object] = T_undefined ; + // table[(T_undefined<<4)+T_double] = T_undefined ; + // table[(T_undefined<<4)+T_float] = T_undefined ; + // table[(T_undefined<<4)+T_boolean] = T_undefined ; + // table[(T_undefined<<4)+T_char] = T_undefined ; + // table[(T_undefined<<4)+T_int] = T_undefined ; + // table[(T_undefined<<4)+T_null] = T_undefined ; + + // table[(T_byte<<4)+T_undefined] = T_undefined ; + table[(T_byte<<4)+T_byte] = (Byte2Int<<12)+(Byte2Int<<4)+T_int ; + table[(T_byte<<4)+T_long] = (Byte2Int<<12)+(Long2Int<<4)+T_int ; + table[(T_byte<<4)+T_short] = (Byte2Int<<12)+(Short2Int<<4)+T_int ; + // table[(T_byte<<4)+T_void] = T_undefined ; + // table[(T_byte<<4)+T_String] = T_undefined ; + // table[(T_byte<<4)+T_Object] = T_undefined ; + // table[(T_byte<<4)+T_double] = T_undefined ; + // table[(T_byte<<4)+T_float] = T_undefined ; + // table[(T_byte<<4)+T_boolean] = T_undefined ; + table[(T_byte<<4)+T_char] = (Byte2Int<<12)+(Char2Int<<4)+T_int ; + table[(T_byte<<4)+T_int] = (Byte2Int<<12)+(Int2Int<<4)+T_int ; + // table[(T_byte<<4)+T_null] = T_undefined ; + + // table[(T_long<<4)+T_undefined] = T_undefined ; + table[(T_long<<4)+T_byte] = (Long2Long<<12)+(Byte2Int<<4)+T_long; + table[(T_long<<4)+T_long] = (Long2Long<<12)+(Long2Int<<4)+T_long ; + table[(T_long<<4)+T_short] = (Long2Long<<12)+(Short2Int<<4)+T_long ; + // table[(T_long<<4)+T_void] = T_undefined ; + // table[(T_long<<4)+T_String] = T_undefined ; + // table[(T_long<<4)+T_Object] = T_undefined ; + // table[(T_long<<4)+T_double] = T_undefined ; + // table[(T_long<<4)+T_float] = T_undefined ; + // table[(T_long<<4)+T_boolean] = T_undefined ; + table[(T_long<<4)+T_char] = (Long2Long<<12)+(Char2Int<<4)+T_long ; + table[(T_long<<4)+T_int] = (Long2Long<<12)+(Int2Int<<4)+T_long ; + // table[(T_long<<4)+T_null] = T_undefined ; + + // table[(T_short<<4)+T_undefined] = T_undefined ; + table[(T_short<<4)+T_byte] = (Short2Int<<12)+(Byte2Int<<4)+T_int ; + table[(T_short<<4)+T_long] = (Short2Int<<12)+(Long2Int<<4)+T_int ; + table[(T_short<<4)+T_short] = (Short2Int<<12)+(Short2Int<<4)+T_int ; + // table[(T_short<<4)+T_void] = T_undefined ; + // table[(T_short<<4)+T_String] = T_undefined ; + // table[(T_short<<4)+T_Object] = T_undefined ; + // table[(T_short<<4)+T_double] = T_undefined ; + // table[(T_short<<4)+T_float] = T_undefined ; + // table[(T_short<<4)+T_boolean] = T_undefined ; + table[(T_short<<4)+T_char] = (Short2Int<<12)+(Char2Int<<4)+T_int ; + table[(T_short<<4)+T_int] = (Short2Int<<12)+(Int2Int<<4)+T_int ; + // table[(T_short<<4)+T_null] = T_undefined ; + + // table[(T_void<<4)+T_undefined] = T_undefined ; + // table[(T_void<<4)+T_byte] = T_undefined ; + // table[(T_void<<4)+T_long] = T_undefined ; + // table[(T_void<<4)+T_short] = T_undefined ; + // table[(T_void<<4)+T_void] = T_undefined ; + // table[(T_void<<4)+T_String] = T_undefined ; + // table[(T_void<<4)+T_Object] = T_undefined ; + // table[(T_void<<4)+T_double] = T_undefined ; + // table[(T_void<<4)+T_float] = T_undefined ; + // table[(T_void<<4)+T_boolean] = T_undefined ; + // table[(T_void<<4)+T_char] = T_undefined ; + // table[(T_void<<4)+T_int] = T_undefined ; + // table[(T_void<<4)+T_null] = T_undefined ; + + // table[(T_String<<4)+T_undefined] = T_undefined ; + // table[(T_String<<4)+T_byte] = T_undefined ; + // table[(T_String<<4)+T_long] = T_undefined ; + // table[(T_String<<4)+T_short] = T_undefined ; + // table[(T_String<<4)+T_void] = T_undefined ; + // table[(T_String<<4)+T_String] = T_undefined ; + // table[(T_String<<4)+T_Object] = T_undefined ; + // table[(T_String<<4)+T_double] = T_undefined ; + // table[(T_String<<4)+T_float] = T_undefined ; + // table[(T_String<<4)+T_boolean] = T_undefined ; + // table[(T_String<<4)+T_char] = T_undefined ; + // table[(T_String<<4)+T_int] = T_undefined ; + // table[(T_String<<4)+T_null] = T_undefined ; + + // table[(T_Object<<4)+T_undefined] = T_undefined ; + // table[(T_Object<<4)+T_byte] = T_undefined ; + // table[(T_Object<<4)+T_long] = T_undefined ; + // table[(T_Object<<4)+T_short] = T_undefined ; + // table[(T_Object<<4)+T_void] = T_undefined ; + // table[(T_Object<<4)+T_String] = T_undefined ; + // table[(T_Object<<4)+T_Object] = T_undefined ; + // table[(T_Object<<4)+T_double] = T_undefined ; + // table[(T_Object<<4)+T_float] = T_undefined ; + // table[(T_Object<<4)+T_boolean] = T_undefined ; + // table[(T_Object<<4)+T_char] = T_undefined ; + // table[(T_Object<<4)+T_int] = T_undefined ; + // table[(T_Object<<4)+T_null] = T_undefined ; + + // table[(T_double<<4)+T_undefined] = T_undefined ; + // table[(T_double<<4)+T_byte] = T_undefined ; + // table[(T_double<<4)+T_long] = T_undefined ; + // table[(T_double<<4)+T_short] = T_undefined ; + // table[(T_double<<4)+T_void] = T_undefined ; + // table[(T_double<<4)+T_String] = T_undefined ; + // table[(T_double<<4)+T_Object] = T_undefined ; + // table[(T_double<<4)+T_double] = T_undefined ; + // table[(T_double<<4)+T_float] = T_undefined ; + // table[(T_double<<4)+T_boolean] = T_undefined ; + // table[(T_double<<4)+T_char] = T_undefined ; + // table[(T_double<<4)+T_int] = T_undefined; + // table[(T_double<<4)+T_null] = T_undefined ; + + // table[(T_float<<4)+T_undefined] = T_undefined ; + // table[(T_float<<4)+T_byte] = T_undefined ; + // table[(T_float<<4)+T_long] = T_undefined ; + // table[(T_float<<4)+T_short] = T_undefined ; + // table[(T_float<<4)+T_void] = T_undefined ; + // table[(T_float<<4)+T_String] = T_undefined ; + // table[(T_float<<4)+T_Object] = T_undefined ; + // table[(T_float<<4)+T_double] = T_undefined ; + // table[(T_float<<4)+T_float] = T_undefined ; + // table[(T_float<<4)+T_boolean] = T_undefined ; + // table[(T_float<<4)+T_char] = T_undefined ; + // table[(T_float<<4)+T_int] = T_undefined ; + // table[(T_float<<4)+T_null] = T_undefined ; + + // table[(T_boolean<<4)+T_undefined] = T_undefined ; + // table[(T_boolean<<4)+T_byte] = T_undefined ; + // table[(T_boolean<<4)+T_long] = T_undefined ; + // table[(T_boolean<<4)+T_short] = T_undefined ; + // table[(T_boolean<<4)+T_void] = T_undefined ; + // table[(T_boolean<<4)+T_String] = T_undefined ; + // table[(T_boolean<<4)+T_Object] = T_undefined ; + // table[(T_boolean<<4)+T_double] = T_undefined ; + // table[(T_boolean<<4)+T_float] = T_undefined ; + // table[(T_boolean<<4)+T_boolean] = T_undefined ; + // table[(T_boolean<<4)+T_char] = T_undefined ; + // table[(T_boolean<<4)+T_int] = T_undefined ; + // table[(T_boolean<<4)+T_null] = T_undefined ; + + // table[(T_char<<4)+T_undefined] = T_undefined ; + table[(T_char<<4)+T_byte] = (Char2Int<<12)+(Byte2Int<<4)+T_int ; + table[(T_char<<4)+T_long] = (Char2Int<<12)+(Long2Int<<4)+T_int ; + table[(T_char<<4)+T_short] = (Char2Int<<12)+(Short2Int<<4)+T_int ; + // table[(T_char<<4)+T_void] = T_undefined ; + // table[(T_char<<4)+T_String] = T_undefined ; + // table[(T_char<<4)+T_Object] = T_undefined ; + // table[(T_char<<4)+T_double] = T_undefined ; + // table[(T_char<<4)+T_float] = T_undefined ; + // table[(T_char<<4)+T_boolean] = T_undefined ; + table[(T_char<<4)+T_char] = (Char2Int<<12)+(Char2Int<<4)+T_int ; + table[(T_char<<4)+T_int] = (Char2Int<<12)+(Int2Int<<4)+T_int ; + // table[(T_char<<4)+T_null] = T_undefined ; + + // table[(T_int<<4)+T_undefined] = T_undefined ; + table[(T_int<<4)+T_byte] = (Int2Int<<12)+(Byte2Int<<4)+T_int ; + table[(T_int<<4)+T_long] = (Int2Int<<12)+(Long2Int<<4)+T_int ; + table[(T_int<<4)+T_short] = (Int2Int<<12)+(Short2Int<<4)+T_int ; + // table[(T_int<<4)+T_void] = T_undefined ; + // table[(T_int<<4)+T_String] = T_undefined ; + // table[(T_int<<4)+T_Object] = T_undefined ; + // table[(T_int<<4)+T_double] = T_undefined ; + // table[(T_int<<4)+T_float] = T_undefined ; + // table[(T_int<<4)+T_boolean] = T_undefined ; + table[(T_int<<4)+T_char] = (Int2Int<<12)+(Char2Int<<4)+T_int ; + table[(T_int<<4)+T_int] = (Int2Int<<12)+(Int2Int<<4)+T_int ; + // table[(T_int<<4)+T_null] = T_undefined ; + + // table[(T_null<<4)+T_undefined] = T_undefined ; + // table[(T_null<<4)+T_byte] = T_undefined ; + // table[(T_null<<4)+T_long] = T_undefined ; + // table[(T_null<<4)+T_short] = T_undefined ; + // table[(T_null<<4)+T_void] = T_undefined ; + // table[(T_null<<4)+T_String] = T_undefined ; + // table[(T_null<<4)+T_Object] = T_undefined ; + // table[(T_null<<4)+T_double] = T_undefined ; + // table[(T_null<<4)+T_float] = T_undefined ; + // table[(T_null<<4)+T_boolean] = T_undefined ; + // table[(T_null<<4)+T_char] = T_undefined ; + // table[(T_null<<4)+T_int] = T_undefined ; + // table[(T_null<<4)+T_null] = T_undefined ; + + return table ; + } + + public static final int[] get_LESS(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + int[] table = new int[16*16] ; + + // table[(T_undefined<<4)+T_undefined] = T_undefined ; + // table[(T_undefined<<4)+T_byte] = T_undefined ; + // table[(T_undefined<<4)+T_long] = T_undefined ; + // table[(T_undefined<<4)+T_short] = T_undefined ; + // table[(T_undefined<<4)+T_void] = T_undefined ; + // table[(T_undefined<<4)+T_String] = T_undefined ; + // table[(T_undefined<<4)+T_Object] = T_undefined ; + // table[(T_undefined<<4)+T_double] = T_undefined ; + // table[(T_undefined<<4)+T_float] = T_undefined ; + // table[(T_undefined<<4)+T_boolean] = T_undefined ; + // table[(T_undefined<<4)+T_char] = T_undefined ; + // table[(T_undefined<<4)+T_int] = T_undefined ; + // table[(T_undefined<<4)+T_null] = T_undefined ; + + // table[(T_byte<<4)+T_undefined] = T_undefined ; + table[(T_byte<<4)+T_byte] = (Byte2Int<<12)+(Byte2Int<<4)+T_boolean ; + table[(T_byte<<4)+T_long] = (Byte2Long<<12)+(Long2Long<<4)+T_boolean ; + table[(T_byte<<4)+T_short] = (Byte2Int<<12)+(Short2Int<<4)+T_boolean ; + // table[(T_byte<<4)+T_void] = T_undefined ; + // table[(T_byte<<4)+T_String] = T_undefined ; + // table[(T_byte<<4)+T_Object] = T_undefined ; + table[(T_byte<<4)+T_double] = (Byte2Double<<12)+(Double2Double<<4)+T_boolean ; + table[(T_byte<<4)+T_float] = (Byte2Float<<12)+(Float2Float<<4)+T_boolean; + // table[(T_byte<<4)+T_boolean] = T_undefined ; + table[(T_byte<<4)+T_char] = (Byte2Int<<12)+(Char2Int<<4)+T_boolean ; + table[(T_byte<<4)+T_int] = (Byte2Int<<12)+(Int2Int<<4)+T_boolean ; + // table[(T_byte<<4)+T_null] = T_undefined ; + + // table[(T_long<<4)+T_undefined] = T_undefined ; + table[(T_long<<4)+T_byte] = (Long2Long<<12)+(Byte2Long<<4)+T_boolean; + table[(T_long<<4)+T_long] = (Long2Long<<12)+(Long2Long<<4)+T_boolean ; + table[(T_long<<4)+T_short] = (Long2Long<<12)+(Short2Long<<4)+T_boolean ; + // table[(T_long<<4)+T_void] = T_undefined ; + // table[(T_long<<4)+T_String] = T_undefined ; + // table[(T_long<<4)+T_Object] = T_undefined ; + table[(T_long<<4)+T_double] = (Long2Double<<12)+(Double2Double<<4)+T_boolean ; + table[(T_long<<4)+T_float] = (Long2Float<<12)+(Float2Float<<4)+T_boolean ; + // table[(T_long<<4)+T_boolean] = T_undefined ; + table[(T_long<<4)+T_char] = (Long2Long<<12)+(Char2Long<<4)+T_boolean ; + table[(T_long<<4)+T_int] = (Long2Long<<12)+(Int2Long<<4)+T_boolean ; + // table[(T_long<<4)+T_null] = T_undefined ; + + // table[(T_short<<4)+T_undefined] = T_undefined ; + table[(T_short<<4)+T_byte] = (Short2Int<<12)+(Byte2Int<<4)+T_boolean ; + table[(T_short<<4)+T_long] = (Short2Long<<12)+(Long2Long<<4)+T_boolean ; + table[(T_short<<4)+T_short] = (Short2Int<<12)+(Short2Int<<4)+T_boolean ; + // table[(T_short<<4)+T_void] = T_undefined ; + // table[(T_short<<4)+T_String] = T_undefined ; + // table[(T_short<<4)+T_Object] = T_undefined ; + table[(T_short<<4)+T_double] = (Short2Double<<12)+(Double2Double<<4)+T_boolean ; + table[(T_short<<4)+T_float] = (Short2Float<<12)+(Float2Float<<4)+T_boolean ; + // table[(T_short<<4)+T_boolean] = T_undefined ; + table[(T_short<<4)+T_char] = (Short2Int<<12)+(Char2Int<<4)+T_boolean ; + table[(T_short<<4)+T_int] = (Short2Int<<12)+(Int2Int<<4)+T_boolean ; + // table[(T_short<<4)+T_null] = T_undefined ; + + // table[(T_void<<4)+T_undefined] = T_undefined ; + // table[(T_void<<4)+T_byte] = T_undefined ; + // table[(T_void<<4)+T_long] = T_undefined ; + // table[(T_void<<4)+T_short] = T_undefined ; + // table[(T_void<<4)+T_void] = T_undefined ; + // table[(T_void<<4)+T_String] = T_undefined ; + // table[(T_void<<4)+T_Object] = T_undefined ; + // table[(T_void<<4)+T_double] = T_undefined ; + // table[(T_void<<4)+T_float] = T_undefined ; + // table[(T_void<<4)+T_boolean] = T_undefined ; + // table[(T_void<<4)+T_char] = T_undefined ; + // table[(T_void<<4)+T_int] = T_undefined ; + // table[(T_void<<4)+T_null] = T_undefined ; + + // table[(T_String<<4)+T_undefined] = T_undefined ; + // table[(T_String<<4)+T_byte] = T_undefined ; + // table[(T_String<<4)+T_long] = T_undefined ; + // table[(T_String<<4)+T_short] = T_undefined ; + // table[(T_String<<4)+T_void] = T_undefined ; + // table[(T_String<<4)+T_String] = T_undefined ; + // table[(T_String<<4)+T_Object] = T_undefined ; + // table[(T_String<<4)+T_double] = T_undefined ; + // table[(T_String<<4)+T_float] = T_undefined ; + // table[(T_String<<4)+T_boolean] = T_undefined ; + // table[(T_String<<4)+T_char] = T_undefined ; + // table[(T_String<<4)+T_int] = T_undefined ; + // table[(T_String<<4)+T_null] = T_undefined ; + + // table[(T_Object<<4)+T_undefined] = T_undefined ; + // table[(T_Object<<4)+T_byte] = T_undefined ; + // table[(T_Object<<4)+T_long] = T_undefined ; + // table[(T_Object<<4)+T_short] = T_undefined ; + // table[(T_Object<<4)+T_void] = T_undefined ; + // table[(T_Object<<4)+T_String] = T_undefined ; + // table[(T_Object<<4)+T_Object] = T_undefined ; + // table[(T_Object<<4)+T_double] = T_undefined ; + // table[(T_Object<<4)+T_float] = T_undefined ; + // table[(T_Object<<4)+T_boolean] = T_undefined ; + // table[(T_Object<<4)+T_char] = T_undefined ; + // table[(T_Object<<4)+T_int] = T_undefined ; + // table[(T_Object<<4)+T_null] = T_undefined ; + + // table[(T_double<<4)+T_undefined] = T_undefined ; + table[(T_double<<4)+T_byte] = (Double2Double<<12)+(Byte2Double<<4)+T_boolean ; + table[(T_double<<4)+T_long] = (Double2Double<<12)+(Long2Double<<4)+T_boolean; + table[(T_double<<4)+T_short] = (Double2Double<<12)+(Short2Double<<4)+T_boolean ; + // table[(T_double<<4)+T_void] = T_undefined ; + // table[(T_double<<4)+T_String] = T_undefined ; + // table[(T_double<<4)+T_Object] = T_undefined ; + table[(T_double<<4)+T_double] = (Double2Double<<12)+(Double2Double<<4)+T_boolean ; + table[(T_double<<4)+T_float] = (Double2Double<<12)+(Float2Double<<4)+T_boolean ; + // table[(T_double<<4)+T_boolean] = T_undefined ; + table[(T_double<<4)+T_char] = (Double2Double<<12)+(Char2Double<<4)+T_boolean ; + table[(T_double<<4)+T_int] = (Double2Double<<12)+(Int2Double<<4)+T_boolean; + // table[(T_double<<4)+T_null] = T_undefined ; + + // table[(T_float<<4)+T_undefined] = T_undefined ; + table[(T_float<<4)+T_byte] = (Float2Float<<12)+(Byte2Float<<4)+T_boolean ; + table[(T_float<<4)+T_long] = (Float2Float<<12)+(Long2Float<<4)+T_boolean ; + table[(T_float<<4)+T_short] = (Float2Float<<12)+(Short2Float<<4)+T_boolean ; + // table[(T_float<<4)+T_void] = T_undefined ; + // table[(T_float<<4)+T_String] = T_undefined ; + // table[(T_float<<4)+T_Object] = T_undefined ; + table[(T_float<<4)+T_double] = (Float2Double<<12)+(Double2Double<<4)+T_boolean ; + table[(T_float<<4)+T_float] = (Float2Float<<12)+(Float2Float<<4)+T_boolean ; + // table[(T_float<<4)+T_boolean] = T_undefined ; + table[(T_float<<4)+T_char] = (Float2Float<<12)+(Char2Float<<4)+T_boolean ; + table[(T_float<<4)+T_int] = (Float2Float<<12)+(Int2Float<<4)+T_boolean ; + // table[(T_float<<4)+T_null] = T_undefined ; + + // table[(T_boolean<<4)+T_undefined] = T_undefined ; + // table[(T_boolean<<4)+T_byte] = T_undefined ; + // table[(T_boolean<<4)+T_long] = T_undefined ; + // table[(T_boolean<<4)+T_short] = T_undefined ; + // table[(T_boolean<<4)+T_void] = T_undefined ; + // table[(T_boolean<<4)+T_String] = T_undefined ; + // table[(T_boolean<<4)+T_Object] = T_undefined ; + // table[(T_boolean<<4)+T_double] = T_undefined ; + // table[(T_boolean<<4)+T_float] = T_undefined ; + // table[(T_boolean<<4)+T_boolean] = T_undefined ; + // table[(T_boolean<<4)+T_char] = T_undefined ; + // table[(T_boolean<<4)+T_int] = T_undefined ; + // table[(T_boolean<<4)+T_null] = T_undefined ; + + // table[(T_char<<4)+T_undefined] = T_undefined ; + table[(T_char<<4)+T_byte] = (Char2Int<<12)+(Byte2Int<<4)+T_boolean ; + table[(T_char<<4)+T_long] = (Char2Long<<12)+(Long2Long<<4)+T_boolean ; + table[(T_char<<4)+T_short] = (Char2Int<<12)+(Short2Int<<4)+T_boolean ; + // table[(T_char<<4)+T_void] = T_undefined ; + // table[(T_char<<4)+T_String] = T_undefined ; + // table[(T_char<<4)+T_Object] = T_undefined ; + table[(T_char<<4)+T_double] = (Char2Double<<12)+(Double2Double<<4)+T_boolean ; + table[(T_char<<4)+T_float] = (Char2Float<<12)+(Float2Float<<4)+T_boolean ; + // table[(T_char<<4)+T_boolean] = T_undefined ; + table[(T_char<<4)+T_char] = (Char2Int<<12)+(Char2Int<<4)+T_boolean ; + table[(T_char<<4)+T_int] = (Char2Int<<12)+(Int2Int<<4)+T_boolean ; + // table[(T_char<<4)+T_null] = T_undefined ; + + // table[(T_int<<4)+T_undefined] = T_undefined ; + table[(T_int<<4)+T_byte] = (Int2Int<<12)+(Byte2Int<<4)+T_boolean ; + table[(T_int<<4)+T_long] = (Int2Long<<12)+(Long2Long<<4)+T_boolean; + table[(T_int<<4)+T_short] = (Int2Int<<12)+(Short2Int<<4)+T_boolean ; + // table[(T_int<<4)+T_void] = T_undefined ; + // table[(T_int<<4)+T_String] = T_undefined ; + // table[(T_int<<4)+T_Object] = T_undefined ; + table[(T_int<<4)+T_double] = (Int2Double<<12)+(Double2Double<<4)+T_boolean ; + table[(T_int<<4)+T_float] = (Int2Float<<12)+(Float2Float<<4)+T_boolean ; + // table[(T_int<<4)+T_boolean] = T_undefined ; + table[(T_int<<4)+T_char] = (Int2Int<<12)+(Char2Int<<4)+T_boolean ; + table[(T_int<<4)+T_int] = (Int2Int<<12)+(Int2Int<<4)+T_boolean; + // table[(T_int<<4)+T_null] = T_undefined ; + + // table[(T_null<<4)+T_undefined] = T_undefined ; + // table[(T_null<<4)+T_byte] = T_undefined ; + // table[(T_null<<4)+T_long] = T_undefined ; + // table[(T_null<<4)+T_short] = T_undefined ; + // table[(T_null<<4)+T_void] = T_undefined ; + // table[(T_null<<4)+T_String] = T_undefined ; + // table[(T_null<<4)+T_Object] = T_undefined ; + // table[(T_null<<4)+T_double] = T_undefined ; + // table[(T_null<<4)+T_float] = T_undefined ; + // table[(T_null<<4)+T_boolean] = T_undefined ; + // table[(T_null<<4)+T_char] = T_undefined ; + // table[(T_null<<4)+T_int] = T_undefined ; + // table[(T_null<<4)+T_null] = T_undefined ; + + return table ; + } + + public static final int[] get_LESS_EQUAL(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + // int[] table = new int[16*16] ; + return get_LESS(); + } + + public static final int[] get_MINUS(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + int[] table = new int[16*16] ; + + table = (int[]) get_PLUS().clone(); + + // customization + table[(T_String<<4)+T_byte] = T_undefined ; + table[(T_String<<4)+T_long] = T_undefined ; + table[(T_String<<4)+T_short] = T_undefined ; + table[(T_String<<4)+T_void] = T_undefined ; + table[(T_String<<4)+T_String] = T_undefined ; + table[(T_String<<4)+T_Object] = T_undefined ; + table[(T_String<<4)+T_double] = T_undefined ; + table[(T_String<<4)+T_float] = T_undefined ; + table[(T_String<<4)+T_boolean] = T_undefined ; + table[(T_String<<4)+T_char] = T_undefined ; + table[(T_String<<4)+T_int] = T_undefined ; + table[(T_String<<4)+T_null] = T_undefined ; + + table[(T_byte<<4) +T_String] = T_undefined ; + table[(T_long<<4) +T_String] = T_undefined ; + table[(T_short<<4) +T_String] = T_undefined ; + table[(T_void<<4) +T_String] = T_undefined ; + table[(T_Object<<4) +T_String] = T_undefined ; + table[(T_double<<4) +T_String] = T_undefined ; + table[(T_float<<4) +T_String] = T_undefined ; + table[(T_boolean<<4)+T_String] = T_undefined ; + table[(T_char<<4) +T_String] = T_undefined ; + table[(T_int<<4) +T_String] = T_undefined ; + table[(T_null<<4) +T_String] = T_undefined ; + + table[(T_null<<4) +T_null] = T_undefined ; + + return table ; + } + + public static final int[] get_MULTIPLY(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + // int[] table = new int[16*16] ; + return get_MINUS(); + } + + public static final int[] get_OR(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + + // int[] table = new int[16*16] ; + return get_AND() ; + } + + public static final int[] get_OR_OR(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + // int[] table = new int[16*16] ; + return get_AND_AND() ; + } + + public static final int[] get_PLUS(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + int[] table = new int[16*16] ; + + // table[(T_undefined<<4)+T_undefined] = T_undefined ; + // table[(T_undefined<<4)+T_byte] = T_undefined ; + // table[(T_undefined<<4)+T_long] = T_undefined ; + // table[(T_undefined<<4)+T_short] = T_undefined ; + // table[(T_undefined<<4)+T_void] = T_undefined ; + // table[(T_undefined<<4)+T_String] = T_undefined ; + // table[(T_undefined<<4)+T_Object] = T_undefined ; + // table[(T_undefined<<4)+T_double] = T_undefined ; + // table[(T_undefined<<4)+T_float] = T_undefined ; + // table[(T_undefined<<4)+T_boolean] = T_undefined ; + // table[(T_undefined<<4)+T_char] = T_undefined ; + // table[(T_undefined<<4)+T_int] = T_undefined ; + // table[(T_undefined<<4)+T_null] = T_undefined ; + + // table[(T_byte<<4)+T_undefined] = T_undefined ; + table[(T_byte<<4)+T_byte] = (Byte2Int<<12)+(Byte2Int<<4)+T_int ; + table[(T_byte<<4)+T_long] = (Byte2Long<<12)+(Long2Long<<4)+T_long ; + table[(T_byte<<4)+T_short] = (Byte2Int<<12)+(Short2Int<<4)+T_int ; + // table[(T_byte<<4)+T_void] = T_undefined ; + table[(T_byte<<4)+T_String] = (Byte2Byte<<12)+(String2String<<4)+T_String ; + // table[(T_byte<<4)+T_Object] = T_undefined ; + table[(T_byte<<4)+T_double] = (Byte2Double<<12)+(Double2Double<<4)+T_double ; + table[(T_byte<<4)+T_float] = (Byte2Float<<12)+(Float2Float<<4)+T_float; + // table[(T_byte<<4)+T_boolean] = T_undefined ; + table[(T_byte<<4)+T_char] = (Byte2Int<<12)+(Char2Int<<4)+T_int ; + table[(T_byte<<4)+T_int] = (Byte2Int<<12)+(Int2Int<<4)+T_int ; + // table[(T_byte<<4)+T_null] = T_undefined ; + + // table[(T_long<<4)+T_undefined] = T_undefined ; + table[(T_long<<4)+T_byte] = (Long2Long<<12)+(Byte2Long<<4)+T_long; + table[(T_long<<4)+T_long] = (Long2Long<<12)+(Long2Long<<4)+T_long ; + table[(T_long<<4)+T_short] = (Long2Long<<12)+(Short2Long<<4)+T_long ; + // table[(T_long<<4)+T_void] = T_undefined ; + table[(T_long<<4)+T_String] = (Long2Long<<12)+(String2String<<4)+T_String ; + // table[(T_long<<4)+T_Object] = T_undefined ; + table[(T_long<<4)+T_double] = (Long2Double<<12)+(Double2Double<<4)+T_double ; + table[(T_long<<4)+T_float] = (Long2Float<<12)+(Float2Float<<4)+T_float ; + // table[(T_long<<4)+T_boolean] = T_undefined ; + table[(T_long<<4)+T_char] = (Long2Long<<12)+(Char2Long<<4)+T_long ; + table[(T_long<<4)+T_int] = (Long2Long<<12)+(Int2Long<<4)+T_long ; ; + // table[(T_long<<4)+T_null] = T_undefined ; + + // table[(T_short<<4)+T_undefined] = T_undefined ; + table[(T_short<<4)+T_byte] = (Short2Int<<12)+(Byte2Int<<4)+T_int ; + table[(T_short<<4)+T_long] = (Short2Long<<12)+(Long2Long<<4)+T_long ; + table[(T_short<<4)+T_short] = (Short2Int<<12)+(Short2Int<<4)+T_int ; + // table[(T_short<<4)+T_void] = T_undefined ; + table[(T_short<<4)+T_String] = (Short2Short<<12)+(String2String<<4)+T_String ; + // table[(T_short<<4)+T_Object] = T_undefined ; + table[(T_short<<4)+T_double] = (Short2Double<<12)+(Double2Double<<4)+T_double ; + table[(T_short<<4)+T_float] = (Short2Float<<12)+(Float2Float<<4)+T_float ; + // table[(T_short<<4)+T_boolean] = T_undefined ; + table[(T_short<<4)+T_char] = (Short2Int<<12)+(Char2Int<<4)+T_int ; + table[(T_short<<4)+T_int] = (Short2Int<<12)+(Int2Int<<4)+T_int ; + // table[(T_short<<4)+T_null] = T_undefined ; + + // table[(T_void<<4)+T_undefined] = T_undefined ; + // table[(T_void<<4)+T_byte] = T_undefined ; + // table[(T_void<<4)+T_long] = T_undefined ; + // table[(T_void<<4)+T_short] = T_undefined ; + // table[(T_void<<4)+T_void] = T_undefined ; + // table[(T_void<<4)+T_String] = T_undefined ; + // table[(T_void<<4)+T_Object] = T_undefined ; + // table[(T_void<<4)+T_double] = T_undefined ; + // table[(T_void<<4)+T_float] = T_undefined ; + // table[(T_void<<4)+T_boolean] = T_undefined ; + // table[(T_void<<4)+T_char] = T_undefined ; + // table[(T_void<<4)+T_int] = T_undefined ; + // table[(T_void<<4)+T_null] = T_undefined ; + + // table[(T_String<<4)+T_undefined] = T_undefined ; + table[(T_String<<4)+T_byte] = (String2String<<12)+(Byte2Byte<<4)+T_String ; + table[(T_String<<4)+T_long] = (String2String<<12)+(Long2Long<<4)+T_String ; + table[(T_String<<4)+T_short] = (String2String<<12)+(Short2Short<<4)+T_String ; + // table[(T_String<<4)+T_void] = T_undefined ; + table[(T_String<<4)+T_String] = (String2String<<12)+(String2String<<4)+T_String ; + table[(T_String<<4)+T_Object] = (String2String<<12)+(Object2Object<<4)+T_String ; + table[(T_String<<4)+T_double] = (String2String<<12)+(Double2Double<<4)+T_String ; + table[(T_String<<4)+T_float] = (String2String<<12)+(Float2Float<<4)+T_String ; + table[(T_String<<4)+T_boolean] = (String2String<<12)+(Boolean2Boolean<<4)+T_String ; + table[(T_String<<4)+T_char] = (String2String<<12)+(Char2Char<<4)+T_String ; + table[(T_String<<4)+T_int] = (String2String<<12)+(Int2Int<<4)+T_String ; + table[(T_String<<4)+T_null] = (String2String<<12)+(T_null<<8)+(T_null<<4)+T_String ; + + // table[(T_Object<<4)+T_undefined] = T_undefined ; + // table[(T_Object<<4)+T_byte] = T_undefined ; + // table[(T_Object<<4)+T_long] = T_undefined ; + // table[(T_Object<<4)+T_short] = T_undefined ; + // table[(T_Object<<4)+T_void] = T_undefined ; + table[(T_Object<<4)+T_String] = (Object2Object<<12)+(String2String<<4)+T_String ; + // table[(T_Object<<4)+T_Object] = T_undefined ; + // table[(T_Object<<4)+T_double] = T_undefined ; + // table[(T_Object<<4)+T_float] = T_undefined ; + // table[(T_Object<<4)+T_boolean] = T_undefined ; + // table[(T_Object<<4)+T_char] = T_undefined ; + // table[(T_Object<<4)+T_int] = T_undefined ; + // table[(T_Object<<4)+T_null] = T_undefined ; + + // table[(T_double<<4)+T_undefined] = T_undefined ; + table[(T_double<<4)+T_byte] = (Double2Double<<12)+(Byte2Double<<4)+T_double ; + table[(T_double<<4)+T_long] = (Double2Double<<12)+(Long2Double<<4)+T_double ; + table[(T_double<<4)+T_short] = (Double2Double<<12)+(Short2Double<<4)+T_double ; ; + // table[(T_double<<4)+T_void] = T_undefined ; + table[(T_double<<4)+T_String] = (Double2Double<<12)+(String2String<<4)+T_String ; + // table[(T_double<<4)+T_Object] = T_undefined ; + table[(T_double<<4)+T_double] = (Double2Double<<12)+(Double2Double<<4)+T_double ; + table[(T_double<<4)+T_float] = (Double2Double<<12)+(Float2Double<<4)+T_double ; ; + // table[(T_double<<4)+T_boolean] = T_undefined ; + table[(T_double<<4)+T_char] = (Double2Double<<12)+(Char2Double<<4)+T_double ; ; + table[(T_double<<4)+T_int] = (Double2Double<<12)+(Int2Double<<4)+T_double ; ; + // table[(T_double<<4)+T_null] = T_undefined ; + + // table[(T_float<<4)+T_undefined] = T_undefined ; + table[(T_float<<4)+T_byte] = (Float2Float<<12)+(Byte2Float<<4)+T_float ; + table[(T_float<<4)+T_long] = (Float2Float<<12)+(Long2Float<<4)+T_float ; + table[(T_float<<4)+T_short] = (Float2Float<<12)+(Short2Float<<4)+T_float ; + // table[(T_float<<4)+T_void] = T_undefined ; + table[(T_float<<4)+T_String] = (Float2Float<<12)+(String2String<<4)+T_String ; + // table[(T_float<<4)+T_Object] = T_undefined ; + table[(T_float<<4)+T_double] = (Float2Double<<12)+(Double2Double<<4)+T_double ; + table[(T_float<<4)+T_float] = (Float2Float<<12)+(Float2Float<<4)+T_float ; + // table[(T_float<<4)+T_boolean] = T_undefined ; + table[(T_float<<4)+T_char] = (Float2Float<<12)+(Char2Float<<4)+T_float ; + table[(T_float<<4)+T_int] = (Float2Float<<12)+(Int2Float<<4)+T_float ; + // table[(T_float<<4)+T_null] = T_undefined ; + + // table[(T_boolean<<4)+T_undefined] = T_undefined ; + // table[(T_boolean<<4)+T_byte] = T_undefined ; + // table[(T_boolean<<4)+T_long] = T_undefined ; + // table[(T_boolean<<4)+T_short] = T_undefined ; + // table[(T_boolean<<4)+T_void] = T_undefined ; + table[(T_boolean<<4)+T_String] = (Boolean2Boolean<<12)+(String2String<<4)+T_String ; + // table[(T_boolean<<4)+T_Object] = T_undefined ; + // table[(T_boolean<<4)+T_double] = T_undefined ; + // table[(T_boolean<<4)+T_float] = T_undefined ; + // table[(T_boolean<<4)+T_boolean] = T_undefined ; + // table[(T_boolean<<4)+T_char] = T_undefined ; + // table[(T_boolean<<4)+T_int] = T_undefined ; + // table[(T_boolean<<4)+T_null] = T_undefined ; + + // table[(T_char<<4)+T_undefined] = T_undefined ; + table[(T_char<<4)+T_byte] = (Char2Int<<12)+(Byte2Int<<4)+T_int ; + table[(T_char<<4)+T_long] = (Char2Long<<12)+(Long2Long<<4)+T_long ; + table[(T_char<<4)+T_short] = (Char2Int<<12)+(Short2Int<<4)+T_int ; + // table[(T_char<<4)+T_void] = T_undefined ; + table[(T_char<<4)+T_String] = (Char2Char<<12)+(String2String<<4)+T_String ; + // table[(T_char<<4)+T_Object] = T_undefined ; + table[(T_char<<4)+T_double] = (Char2Double<<12)+(Double2Double<<4)+T_double ; + table[(T_char<<4)+T_float] = (Char2Float<<12)+(Float2Float<<4)+T_float ; + // table[(T_char<<4)+T_boolean] = T_undefined ; + table[(T_char<<4)+T_char] = (Char2Int<<12)+(Char2Int<<4)+T_int ; ; + table[(T_char<<4)+T_int] = (Char2Int<<12)+(Int2Int<<4)+T_int ; + // table[(T_char<<4)+T_null] = T_undefined ; + + // table[(T_int<<4)+T_undefined] = T_undefined ; + table[(T_int<<4)+T_byte] = (Int2Int<<12)+(Byte2Int<<4)+T_int ; + table[(T_int<<4)+T_long] = (Int2Long<<12)+(Long2Long<<4)+T_long ; + table[(T_int<<4)+T_short] = (Int2Int<<12)+(Short2Int<<4)+T_int ; + // table[(T_int<<4)+T_void] = T_undefined ; + table[(T_int<<4)+T_String] = (Int2Int<<12)+(String2String<<4)+T_String ; + // table[(T_int<<4)+T_Object] = T_undefined ; + table[(T_int<<4)+T_double] = (Int2Double<<12)+(Double2Double<<4)+T_double ; + table[(T_int<<4)+T_float] = (Int2Float<<12)+(Float2Float<<4)+T_float ; + // table[(T_int<<4)+T_boolean] = T_undefined ; + table[(T_int<<4)+T_char] = (Int2Int<<12)+(Char2Int<<4)+T_int ; + table[(T_int<<4)+T_int] = (Int2Int<<12)+(Int2Int<<4)+T_int ; + // table[(T_int<<4)+T_null] = T_undefined ; + + // table[(T_null<<4)+T_undefined] = T_undefined ; + // table[(T_null<<4)+T_byte] = T_undefined ; + // table[(T_null<<4)+T_long] = T_undefined ; + // table[(T_null<<4)+T_short] = T_undefined ; + // table[(T_null<<4)+T_void] = T_undefined ; + table[(T_null<<4)+T_String] = (T_null<<16)+(T_null<<12)+(String2String<<4)+T_String ; + // table[(T_null<<4)+T_Object] = T_undefined ; + // table[(T_null<<4)+T_double] = T_undefined ; + // table[(T_null<<4)+T_float] = T_undefined ; + // table[(T_null<<4)+T_boolean] = T_undefined ; + // table[(T_null<<4)+T_char] = T_undefined ; + // table[(T_null<<4)+T_int] = T_undefined ; + // table[(T_null<<4)+T_null] = (Null2String<<12)+(Null2String<<4)+T_String ;; + + return table ; + } + + public static final int[] get_REMAINDER(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + // int[] table = new int[16*16] ; + return get_MINUS(); + } + + public static final int[] get_RIGHT_SHIFT(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + // int[] table = new int[16*16] ; + return get_LEFT_SHIFT(); + } + + public static final int[] get_UNSIGNED_RIGHT_SHIFT(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + // int[] table = new int[16*16] ; + return get_LEFT_SHIFT(); + } + + public static final int[] get_XOR(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + // int[] table = new int[16*16] ; + return get_AND() ; + } + + public String operatorToString() { + switch ((bits & OperatorMASK) >> OperatorSHIFT) { + case EQUAL_EQUAL : + return "=="; //$NON-NLS-1$ + case LESS_EQUAL : + return "<="; //$NON-NLS-1$ + case GREATER_EQUAL : + return ">="; //$NON-NLS-1$ + case NOT_EQUAL : + return "!="; //$NON-NLS-1$ + case LEFT_SHIFT : + return "<<"; //$NON-NLS-1$ + case RIGHT_SHIFT : + return ">>"; //$NON-NLS-1$ + case UNSIGNED_RIGHT_SHIFT : + return ">>>"; //$NON-NLS-1$ + case OR_OR : + return "||"; //$NON-NLS-1$ + case AND_AND : + return "&&"; //$NON-NLS-1$ + case PLUS : + return "+"; //$NON-NLS-1$ + case MINUS : + return "-"; //$NON-NLS-1$ + case NOT : + return "!"; //$NON-NLS-1$ + case REMAINDER : + return "%"; //$NON-NLS-1$ + case XOR : + return "^"; //$NON-NLS-1$ + case AND : + return "&"; //$NON-NLS-1$ + case MULTIPLY : + return "*"; //$NON-NLS-1$ + case OR : + return "|"; //$NON-NLS-1$ + case TWIDDLE : + return "~"; //$NON-NLS-1$ + case DIVIDE : + return "/"; //$NON-NLS-1$ + case GREATER : + return ">"; //$NON-NLS-1$ + case LESS : + return "<"; //$NON-NLS-1$ + case QUESTIONCOLON : + return "?:"; //$NON-NLS-1$ + case EQUAL : + return "="; //$NON-NLS-1$ + }; + return "unknown operator"; //$NON-NLS-1$ + } + + public String toStringExpression(){ + + //subclass redefine toStringExpressionNoParenthesis() + return "(" + toStringExpressionNoParenthesis() + ")"; //$NON-NLS-2$ //$NON-NLS-1$ + } + + public abstract String toStringExpressionNoParenthesis(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/OperatorIds.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/OperatorIds.java new file mode 100644 index 0000000..1246180 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/OperatorIds.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +public interface OperatorIds { + public static final int AND_AND = 0; + public static final int OR_OR = 1; + public static final int AND = 2; + public static final int OR = 3; + public static final int LESS = 4; + public static final int LESS_EQUAL = 5; + public static final int GREATER = 6; + public static final int GREATER_EQUAL = 7; + public static final int XOR = 8; + public static final int DIVIDE = 9; + public static final int LEFT_SHIFT = 10; + public static final int NOT = 11; + public static final int TWIDDLE = 12; + public static final int MINUS = 13; + public static final int PLUS = 14; + public static final int MULTIPLY = 15; + public static final int REMAINDER = 16; + public static final int RIGHT_SHIFT = 17; + public static final int EQUAL_EQUAL = 18; + public static final int UNSIGNED_RIGHT_SHIFT= 19; + public static final int NumberOfTables = 20; + + public static final int QUESTIONCOLON = 23; + + public static final int NOT_EQUAL = 29; + public static final int EQUAL = 30; + public static final int INSTANCEOF = 31; + public static final int PLUS_PLUS = 32; + public static final int MINUS_MINUS = 33; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/PostfixExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/PostfixExpression.java new file mode 100644 index 0000000..97f691c --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/PostfixExpression.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class PostfixExpression extends CompoundAssignment { + + public PostfixExpression(Expression l, Expression e, int op, int pos) { + + super(l, e, op, pos); + this.sourceStart = l.sourceStart; + this.sourceEnd = pos; + } + + /** + * Code generation for PostfixExpression + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + // various scenarii are possible, setting an array reference, + // a field reference, a blank final field reference, a field of an enclosing instance or + // just a local variable. + + int pc = codeStream.position; + lhs.generatePostIncrement(currentScope, codeStream, this, valueRequired); + if (valueRequired) { + codeStream.generateImplicitConversion(implicitConversion); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public String operatorToString() { + switch (operator) { + case PLUS : + return "++"; //$NON-NLS-1$ + case MINUS : + return "--"; //$NON-NLS-1$ + } + return "unknown operator"; //$NON-NLS-1$ + } + + public boolean restrainUsageToNumericTypes() { + + return true; + } + + public String toStringExpressionNoParenthesis() { + + return lhs.toStringExpression() + " " + operatorToString(); //$NON-NLS-1$ + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + lhs.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/PrefixExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/PrefixExpression.java new file mode 100644 index 0000000..35dcd6c --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/PrefixExpression.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class PrefixExpression extends CompoundAssignment { + + /** + * PrefixExpression constructor comment. + * @param l org.eclipse.jdt.internal.compiler.ast.Expression + * @param r org.eclipse.jdt.internal.compiler.ast.Expression + * @param op int + */ + public PrefixExpression(Expression l, Expression e, int op, int pos) { + + super(l, e, op, l.sourceEnd); + this.sourceStart = pos; + this.sourceEnd = l.sourceEnd; + } + + public String operatorToString() { + + switch (operator) { + case PLUS : + return "++"; //$NON-NLS-1$ + case MINUS : + return "--"; //$NON-NLS-1$ + } + return "unknown operator"; //$NON-NLS-1$ + } + + public boolean restrainUsageToNumericTypes() { + + return true; + } + + public String toStringExpressionNoParenthesis() { + + return operatorToString() + " " + lhs.toStringExpression(); //$NON-NLS-1$ + + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + lhs.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/QualifiedAllocationExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/QualifiedAllocationExpression.java new file mode 100644 index 0000000..da1555d --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/QualifiedAllocationExpression.java @@ -0,0 +1,340 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class QualifiedAllocationExpression extends AllocationExpression { + + //qualification may be on both side + public Expression enclosingInstance; + public AnonymousLocalTypeDeclaration anonymousType; + + public QualifiedAllocationExpression() { + } + + public QualifiedAllocationExpression(AnonymousLocalTypeDeclaration anonymousType) { + this.anonymousType = anonymousType; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // variation on allocation, where can be specified an enclosing instance and an anonymous type + + // analyse the enclosing instance + if (enclosingInstance != null) { + flowInfo = enclosingInstance.analyseCode(currentScope, flowContext, flowInfo); + } + // process arguments + if (arguments != null) { + for (int i = 0, count = arguments.length; i < count; i++) { + flowInfo = arguments[i].analyseCode(currentScope, flowContext, flowInfo); + } + } + + // analyse the anonymous nested type + if (anonymousType != null) { + flowInfo = anonymousType.analyseCode(currentScope, flowContext, flowInfo); + } + + // record some dependency information for exception types + ReferenceBinding[] thrownExceptions; + if (((thrownExceptions = binding.thrownExceptions).length) != 0) { + // check exception handling + flowContext.checkExceptionHandlers( + thrownExceptions, + this, + flowInfo, + currentScope); + } + manageEnclosingInstanceAccessIfNecessary(currentScope); + manageSyntheticAccessIfNecessary(currentScope); + return flowInfo; + } + + public Expression enclosingInstance() { + + return enclosingInstance; + } + + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + ReferenceBinding allocatedType = binding.declaringClass; + if (allocatedType.isLocalType()) { + LocalTypeBinding localType = (LocalTypeBinding) allocatedType; + localType.constantPoolName( + codeStream.classFile.outerMostEnclosingClassFile().computeConstantPoolName( + localType)); + } + codeStream.new_(allocatedType); + if (valueRequired) { + codeStream.dup(); + } + // better highlight for allocation: display the type individually + codeStream.recordPositionsFrom(pc, type.sourceStart); + + // handling innerclass instance allocation + if (allocatedType.isNestedType()) { + // make sure its name is computed before arguments, since may be necessary for argument emulation + codeStream.generateSyntheticArgumentValues( + currentScope, + allocatedType, + enclosingInstance(), + this); + } + // generate the arguments for constructor + if (arguments != null) { + for (int i = 0, count = arguments.length; i < count; i++) { + arguments[i].generateCode(currentScope, codeStream, true); + } + } + // invoke constructor + if (syntheticAccessor == null) { + codeStream.invokespecial(binding); + } else { + // synthetic accessor got some extra arguments appended to its signature, which need values + for (int i = 0, + max = syntheticAccessor.parameters.length - binding.parameters.length; + i < max; + i++) { + codeStream.aconst_null(); + } + codeStream.invokespecial(syntheticAccessor); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + if (anonymousType != null) { + anonymousType.generateCode(currentScope, codeStream); + } + } + + public boolean isSuperAccess() { + + // necessary to lookup super constructor of anonymous type + return anonymousType != null; + } + + /* Inner emulation consists in either recording a dependency + * link only, or performing one level of propagation. + * + * Dependency mechanism is used whenever dealing with source target + * types, since by the time we reach them, we might not yet know their + * exact need. + */ + public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) { + + ReferenceBinding allocatedType; + + // perform some emulation work in case there is some and we are inside a local type only + if ((allocatedType = binding.declaringClass).isNestedType() + && currentScope.enclosingSourceType().isLocalType()) { + + if (allocatedType.isLocalType()) { + ((LocalTypeBinding) allocatedType).addInnerEmulationDependent( + currentScope, + enclosingInstance != null, + false); + // request cascade of accesses + } else { + // locally propagate, since we already now the desired shape for sure + currentScope.propagateInnerEmulation( + allocatedType, + enclosingInstance != null, + false); + // request cascade of accesses + } + } + } + + public TypeBinding resolveType(BlockScope scope) { + + if (anonymousType == null && enclosingInstance == null) + return super.resolveType(scope); + // added for code assist... is not possible with 'normal' code + + // Propagate the type checking to the arguments, and checks if the constructor is defined. + + // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt + // ClassInstanceCreationExpression ::= Name '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt + // ==> by construction, when there is an enclosing instance the typename may NOT be qualified + // ==> therefore by construction the type is always a SingleTypeReferenceType instead of being either + // sometime a SingleTypeReference and sometime a QualifedTypeReference + + constant = NotAConstant; + TypeBinding enclosingInstTb = null; + TypeBinding recType; + if (anonymousType == null) { + //----------------no anonymous class------------------------ + if ((enclosingInstTb = enclosingInstance.resolveType(scope)) == null) + return null; + if (enclosingInstTb.isBaseType() | enclosingInstTb.isArrayType()) { + scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance( + enclosingInstTb, + enclosingInstance); + return null; + } + recType = + ((SingleTypeReference) type).resolveTypeEnclosing( + scope, + (ReferenceBinding) enclosingInstTb); + // will check for null after args are resolved + TypeBinding[] argumentTypes = NoParameters; + if (arguments != null) { + boolean argHasError = false; + int length = arguments.length; + argumentTypes = new TypeBinding[length]; + for (int i = 0; i < length; i++) + if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null) + argHasError = true; + if (argHasError) + return recType; + } + if (recType == null) + return null; + if (!recType.canBeInstantiated()) { + scope.problemReporter().cannotInstantiate(type, recType); + return recType; + } + if ((binding = + scope.getConstructor((ReferenceBinding) recType, argumentTypes, this)) + .isValidBinding()) { + if (isMethodUseDeprecated(binding, scope)) + scope.problemReporter().deprecatedMethod(binding, this); + + if (arguments != null) + for (int i = 0; i < arguments.length; i++) + arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]); + } else { + if (binding.declaringClass == null) + binding.declaringClass = (ReferenceBinding) recType; + scope.problemReporter().invalidConstructor(this, binding); + return recType; + } + + // The enclosing instance must be compatible with the innermost enclosing type + ReferenceBinding expectedType = binding.declaringClass.enclosingType(); + if (scope.areTypesCompatible(enclosingInstTb, expectedType)) + return recType; + scope.problemReporter().typeMismatchErrorActualTypeExpectedType( + enclosingInstance, + enclosingInstTb, + expectedType); + return recType; + } + + //--------------there is an anonymous type declaration----------------- + if (enclosingInstance != null) { + if ((enclosingInstTb = enclosingInstance.resolveType(scope)) == null) + return null; + if (enclosingInstTb.isBaseType() | enclosingInstTb.isArrayType()) { + scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance( + enclosingInstTb, + enclosingInstance); + return null; + } + } + // due to syntax-construction, recType is a ReferenceBinding + recType = + (enclosingInstance == null) + ? type.resolveType(scope) + : ((SingleTypeReference) type).resolveTypeEnclosing( + scope, + (ReferenceBinding) enclosingInstTb); + if (recType == null) + return null; + if (((ReferenceBinding) recType).isFinal()) { + scope.problemReporter().anonymousClassCannotExtendFinalClass(type, recType); + return null; + } + TypeBinding[] argumentTypes = NoParameters; + if (arguments != null) { + int length = arguments.length; + argumentTypes = new TypeBinding[length]; + for (int i = 0; i < length; i++) + if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null) + return null; + } + + // an anonymous class inherits from java.lang.Object when declared "after" an interface + ReferenceBinding superBinding = + recType.isInterface() ? scope.getJavaLangObject() : (ReferenceBinding) recType; + MethodBinding inheritedBinding = + scope.getConstructor(superBinding, argumentTypes, this); + if (!inheritedBinding.isValidBinding()) { + if (inheritedBinding.declaringClass == null) + inheritedBinding.declaringClass = superBinding; + scope.problemReporter().invalidConstructor(this, inheritedBinding); + return null; + } + if (enclosingInstance != null) { + if (!scope + .areTypesCompatible( + enclosingInstTb, + inheritedBinding.declaringClass.enclosingType())) { + scope.problemReporter().typeMismatchErrorActualTypeExpectedType( + enclosingInstance, + enclosingInstTb, + inheritedBinding.declaringClass.enclosingType()); + return null; + } + } + + // this promotion has to be done somewhere: here or inside the constructor of the + // anonymous class. We do it here while the constructor of the inner is then easier. + if (arguments != null) + for (int i = 0; i < arguments.length; i++) + arguments[i].implicitWidening(inheritedBinding.parameters[i], argumentTypes[i]); + + // Update the anonymous inner class : superclass, interface + scope.addAnonymousType(anonymousType, (ReferenceBinding) recType); + anonymousType.resolve(scope); + binding = anonymousType.createsInternalConstructorWithBinding(inheritedBinding); + return anonymousType.binding; // 1.2 change + } + + public String toStringExpression(int tab) { + + String s = ""; //$NON-NLS-1$ + if (enclosingInstance != null) + s += enclosingInstance.toString() + "."; //$NON-NLS-1$ + s += super.toStringExpression(tab); + if (anonymousType != null) { + s += anonymousType.toString(tab); + } //allows to restart just after the } one line under .... + return s; + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + if (enclosingInstance != null) + enclosingInstance.traverse(visitor, scope); + type.traverse(visitor, scope); + if (arguments != null) { + int argumentsLength = arguments.length; + for (int i = 0; i < argumentsLength; i++) + arguments[i].traverse(visitor, scope); + } + if (anonymousType != null) + anonymousType.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/QualifiedNameReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/QualifiedNameReference.java new file mode 100644 index 0000000..321949f --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/QualifiedNameReference.java @@ -0,0 +1,801 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class QualifiedNameReference extends NameReference { + + public char[][] tokens; + public FieldBinding[] otherBindings, otherCodegenBindings; + int[] otherDepths; + public int indexOfFirstFieldBinding;//points (into tokens) for the first token that corresponds to first FieldBinding + SyntheticAccessMethodBinding syntheticWriteAccessor; + SyntheticAccessMethodBinding[] syntheticReadAccessors; + protected FieldBinding lastFieldBinding; + public QualifiedNameReference( + char[][] sources, + int sourceStart, + int sourceEnd) { + super(); + tokens = sources; + this.sourceStart = sourceStart; + this.sourceEnd = sourceEnd; + } + public FlowInfo analyseAssignment( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo, + Assignment assignment, + boolean isCompound) { + + if (assignment.expression != null) { + flowInfo = + assignment + .expression + .analyseCode(currentScope, flowContext, flowInfo) + .unconditionalInits(); + } + // determine the rank until which we now we do not need any actual value for the field access + int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length; + int indexOfFirstValueRequired = otherBindingsCount; + while (indexOfFirstValueRequired > 0) { + FieldBinding otherBinding = otherBindings[indexOfFirstValueRequired - 1]; + if (otherBinding.isStatic()) + break; // no longer need any value before this point + indexOfFirstValueRequired--; + } + FieldBinding lastFieldBinding = null; + if ((bits & FIELD) != 0) { + // reading from a field + // check if final blank field + if ((lastFieldBinding = (FieldBinding) binding).isFinal() + && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) { + if (!flowInfo.isDefinitelyAssigned(lastFieldBinding)) { + currentScope.problemReporter().uninitializedBlankFinalField( + lastFieldBinding, + this); + } + } + } else { + if ((bits & LOCAL) != 0) { + // first binding is a local variable + LocalVariableBinding localBinding; + if (!flowInfo + .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) { + currentScope.problemReporter().uninitializedLocalVariable(localBinding, this); + } + if (!flowInfo.isFakeReachable()) + localBinding.used = true; + } + } + if (indexOfFirstValueRequired == 0) { + manageEnclosingInstanceAccessIfNecessary(currentScope); + // only for first binding + } + // all intermediate field accesses are read accesses + if (otherBindings != null) { + int start = indexOfFirstValueRequired == 0 ? 0 : indexOfFirstValueRequired - 1; + for (int i = start; i < otherBindingsCount; i++) { + if (lastFieldBinding != null) { // could be null if first was a local variable + TypeBinding lastReceiverType; + switch(i){ + case 0 : + lastReceiverType = this.actualReceiverType; + break; + case 1 : + lastReceiverType = ((VariableBinding)binding).type; + break; + default : + lastReceiverType = otherBindings[i-1].type; + } + manageSyntheticReadAccessIfNecessary( + currentScope, + lastFieldBinding, + lastReceiverType, + i); + } + lastFieldBinding = otherBindings[i]; + } + } + if (isCompound) { + if (binding == lastFieldBinding + && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding) + && (!flowInfo.isDefinitelyAssigned(lastFieldBinding))) { + currentScope.problemReporter().uninitializedBlankFinalField( + lastFieldBinding, + this); + } + TypeBinding lastReceiverType; + if (lastFieldBinding == binding){ + lastReceiverType = this.actualReceiverType; + } else if (otherBindingsCount == 1){ + lastReceiverType = ((VariableBinding)this.binding).type; + } else { + lastReceiverType = this.otherBindings[otherBindingsCount-2].type; + } + manageSyntheticReadAccessIfNecessary( + currentScope, + lastFieldBinding, + lastReceiverType, + lastFieldBinding == binding + ? 0 + : otherBindingsCount); + } + // the last field access is a write access + if (lastFieldBinding.isFinal()) { + // in a context where it can be assigned? + if (currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) { + if (flowInfo.isPotentiallyAssigned(lastFieldBinding)) { + if (indexOfFirstFieldBinding == 1) { + // was an implicit reference to the first field binding + currentScope.problemReporter().duplicateInitializationOfBlankFinalField( + lastFieldBinding, + this); + } else { + currentScope.problemReporter().cannotAssignToFinalField(lastFieldBinding, this); + // attempting to assign a non implicit reference + } + } + flowInfo.markAsDefinitelyAssigned(lastFieldBinding); + flowContext.recordSettingFinal(lastFieldBinding, this); + } else { + currentScope.problemReporter().cannotAssignToFinalField(lastFieldBinding, this); + } + } + // equivalent to valuesRequired[maxOtherBindings] + TypeBinding lastReceiverType; + if (lastFieldBinding == binding){ + lastReceiverType = this.actualReceiverType; + } else if (otherBindingsCount == 1){ + lastReceiverType = ((VariableBinding)this.binding).type; + } else { + lastReceiverType = this.otherBindings[otherBindingsCount-2].type; + } + manageSyntheticWriteAccessIfNecessary(currentScope, lastFieldBinding, lastReceiverType); + + return flowInfo; + } + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + return analyseCode(currentScope, flowContext, flowInfo, true); + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo, + boolean valueRequired) { + + // determine the rank until which we now we do not need any actual value for the field access + int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length; + int indexOfFirstValueRequired; + if (valueRequired) { + indexOfFirstValueRequired = otherBindingsCount; + while (indexOfFirstValueRequired > 0) { + FieldBinding otherBinding = otherBindings[indexOfFirstValueRequired - 1]; + if (otherBinding.isStatic()) + break; // no longer need any value before this point + indexOfFirstValueRequired--; + } + } else { + indexOfFirstValueRequired = otherBindingsCount + 1; + } + switch (bits & RestrictiveFlagMASK) { + case FIELD : // reading a field + if (indexOfFirstValueRequired == 0) { + manageSyntheticReadAccessIfNecessary(currentScope, (FieldBinding) binding, this.actualReceiverType, 0); + } + // check if reading a final blank field + FieldBinding fieldBinding; + if ((fieldBinding = (FieldBinding) binding).isFinal() + && (indexOfFirstFieldBinding == 1) + // was an implicit reference to the first field binding + && currentScope.allowBlankFinalFieldAssignment(fieldBinding) + && (!flowInfo.isDefinitelyAssigned(fieldBinding))) { + currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); + } + break; + case LOCAL : // reading a local variable + LocalVariableBinding localBinding; + if (!flowInfo + .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) { + currentScope.problemReporter().uninitializedLocalVariable(localBinding, this); + } + if (!flowInfo.isFakeReachable()) + localBinding.used = true; + } + if (indexOfFirstValueRequired == 0) { + manageEnclosingInstanceAccessIfNecessary(currentScope); + // only for first binding + } + if (otherBindings != null) { + int start = indexOfFirstValueRequired == 0 ? 0 : indexOfFirstValueRequired - 1; + for (int i = start; i < otherBindingsCount; i++) { + manageSyntheticReadAccessIfNecessary( + currentScope, + otherBindings[i], + i == 0 + ? ((VariableBinding)binding).type + : otherBindings[i-1].type, + i + 1); + } + } + return flowInfo; + } + /** + * Check and/or redirect the field access to the delegate receiver if any + */ + public TypeBinding checkFieldAccess(BlockScope scope) { + // check for forward references + FieldBinding fieldBinding = (FieldBinding) binding; + MethodScope methodScope = scope.methodScope(); + if (methodScope.enclosingSourceType() == fieldBinding.declaringClass + && methodScope.fieldDeclarationIndex != methodScope.NotInFieldDecl + && fieldBinding.id >= methodScope.fieldDeclarationIndex) { + if ((!fieldBinding.isStatic() || methodScope.isStatic) + && this.indexOfFirstFieldBinding == 1) + scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType()); + } + bits &= ~RestrictiveFlagMASK; // clear bits + bits |= FIELD; + return getOtherFieldBindings(scope); + } + public void generateAssignment( + BlockScope currentScope, + CodeStream codeStream, + Assignment assignment, + boolean valueRequired) { + + generateReadSequence(currentScope, codeStream, true); + assignment.expression.generateCode(currentScope, codeStream, true); + fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, valueRequired); + // equivalent to valuesRequired[maxOtherBindings] + if (valueRequired) { + codeStream.generateImplicitConversion(assignment.implicitConversion); + } + } + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + int pc = codeStream.position; + if (constant != NotAConstant) { + if (valueRequired) { + codeStream.generateConstant(constant, implicitConversion); + } + } else { + generateReadSequence(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (lastFieldBinding.declaringClass == null) { // array length + codeStream.arraylength(); + codeStream.generateImplicitConversion(implicitConversion); + } else { + if (lastFieldBinding.constant != NotAConstant) { + // inline the last field constant + codeStream.generateConstant(lastFieldBinding.constant, implicitConversion); + } else { + SyntheticAccessMethodBinding accessor = + syntheticReadAccessors == null + ? null + : syntheticReadAccessors[syntheticReadAccessors.length - 1]; + if (accessor == null) { + if (lastFieldBinding.isStatic()) { + codeStream.getstatic(lastFieldBinding); + } else { + codeStream.getfield(lastFieldBinding); + } + } else { + codeStream.invokestatic(accessor); + } + codeStream.generateImplicitConversion(implicitConversion); + } + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + public void generateCompoundAssignment( + BlockScope currentScope, + CodeStream codeStream, + Expression expression, + int operator, + int assignmentImplicitConversion, + boolean valueRequired) { + + generateReadSequence(currentScope, codeStream, true); + SyntheticAccessMethodBinding accessor = + syntheticReadAccessors == null + ? null + : syntheticReadAccessors[syntheticReadAccessors.length - 1]; + if (lastFieldBinding.isStatic()) { + if (accessor == null) { + codeStream.getstatic(lastFieldBinding); + } else { + codeStream.invokestatic(accessor); + } + } else { + codeStream.dup(); + if (accessor == null) { + codeStream.getfield(lastFieldBinding); + } else { + codeStream.invokestatic(accessor); + } + } + // the last field access is a write access + // perform the actual compound operation + int operationTypeID; + if ((operationTypeID = implicitConversion >> 4) == T_String) { + codeStream.generateStringAppend(currentScope, null, expression); + } else { + // promote the array reference to the suitable operation type + codeStream.generateImplicitConversion(implicitConversion); + // generate the increment value (will by itself be promoted to the operation value) + if (expression == IntLiteral.One) { // prefix operation + codeStream.generateConstant(expression.constant, implicitConversion); + } else { + expression.generateCode(currentScope, codeStream, true); + } + // perform the operation + codeStream.sendOperator(operator, operationTypeID); + // cast the value back to the array reference type + codeStream.generateImplicitConversion(assignmentImplicitConversion); + } + // actual assignment + fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, valueRequired); + // equivalent to valuesRequired[maxOtherBindings] + } + public void generatePostIncrement( + BlockScope currentScope, + CodeStream codeStream, + CompoundAssignment postIncrement, + boolean valueRequired) { + generateReadSequence(currentScope, codeStream, true); + SyntheticAccessMethodBinding accessor = + syntheticReadAccessors == null + ? null + : syntheticReadAccessors[syntheticReadAccessors.length - 1]; + if (lastFieldBinding.isStatic()) { + if (accessor == null) { + codeStream.getstatic(lastFieldBinding); + } else { + codeStream.invokestatic(accessor); + } + } else { + codeStream.dup(); + if (accessor == null) { + codeStream.getfield(lastFieldBinding); + } else { + codeStream.invokestatic(accessor); + } + } + // duplicate the old field value + if (valueRequired) { + if (lastFieldBinding.isStatic()) { + if ((lastFieldBinding.type == LongBinding) + || (lastFieldBinding.type == DoubleBinding)) { + codeStream.dup2(); + } else { + codeStream.dup(); + } + } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value] + if ((lastFieldBinding.type == LongBinding) + || (lastFieldBinding.type == DoubleBinding)) { + codeStream.dup2_x1(); + } else { + codeStream.dup_x1(); + } + } + } + codeStream.generateConstant( + postIncrement.expression.constant, + implicitConversion); + codeStream.sendOperator(postIncrement.operator, lastFieldBinding.type.id); + codeStream.generateImplicitConversion( + postIncrement.assignmentImplicitConversion); + fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, false); + } + /* + * Generate code for all bindings (local and fields) excluding the last one, which may then be generated code + * for a read or write access. + */ + public void generateReadSequence( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + // determine the rank until which we now we do not need any actual value for the field access + int otherBindingsCount = this.otherCodegenBindings == null ? 0 : otherCodegenBindings.length; + int indexOfFirstValueRequired; + if (valueRequired) { + indexOfFirstValueRequired = otherBindingsCount; + while (indexOfFirstValueRequired > 0) { + FieldBinding otherBinding = this.otherCodegenBindings[indexOfFirstValueRequired - 1]; + if (otherBinding.isStatic() || otherBinding.constant != NotAConstant) + break; // no longer need any value before this point + indexOfFirstValueRequired--; + } + } else { + indexOfFirstValueRequired = otherBindingsCount + 1; + } + if (indexOfFirstValueRequired == 0) { + switch (bits & RestrictiveFlagMASK) { + case FIELD : + lastFieldBinding = (FieldBinding) this.codegenBinding; + // if first field is actually constant, we can inline it + if (lastFieldBinding.constant != NotAConstant) { + codeStream.generateConstant(lastFieldBinding.constant, 0); + // no implicit conversion + lastFieldBinding = null; // will not generate it again + break; + } + if (!lastFieldBinding.isStatic()) { + if ((bits & DepthMASK) != 0) { + Object[] emulationPath = + currentScope.getExactEmulationPath( + currentScope.enclosingSourceType().enclosingTypeAt( + (bits & DepthMASK) >> DepthSHIFT)); + if (emulationPath == null) { + // internal error, per construction we should have found it + currentScope.problemReporter().needImplementation(); + } else { + codeStream.generateOuterAccess(emulationPath, this, currentScope); + } + } else { + generateReceiver(codeStream); + } + } + break; + case LOCAL : // reading the first local variable + lastFieldBinding = null; + LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; + // regular local variable read + if (localBinding.constant != NotAConstant) { + codeStream.generateConstant(localBinding.constant, 0); + // no implicit conversion + } else { + // outer local? + if ((bits & DepthMASK) != 0) { + // outer local can be reached either through a synthetic arg or a synthetic field + VariableBinding[] path = currentScope.getEmulationPath(localBinding); + if (path == null) { + // emulation was not possible (should not happen per construction) + currentScope.problemReporter().needImplementation(); + } else { + codeStream.generateOuterAccess(path, this, currentScope); + } + } else { + codeStream.load(localBinding); + } + } + } + } else { + lastFieldBinding = null; + } + // all intermediate field accesses are read accesses + // only the last field binding is a write access + if (this.otherCodegenBindings != null) { + int start = indexOfFirstValueRequired == 0 ? 0 : indexOfFirstValueRequired - 1; + for (int i = start; i < otherBindingsCount; i++) { + if (lastFieldBinding != null) { + MethodBinding accessor = + syntheticReadAccessors == null ? null : syntheticReadAccessors[i]; + if (accessor == null) + if (lastFieldBinding.isStatic()) + codeStream.getstatic(lastFieldBinding); + else + codeStream.getfield(lastFieldBinding); + else + codeStream.invokestatic(accessor); + } + lastFieldBinding = otherCodegenBindings[i]; + } + } + } + public void generateReceiver(CodeStream codeStream) { + codeStream.aload_0(); + } + public TypeBinding getOtherFieldBindings(BlockScope scope) { + // At this point restrictiveFlag may ONLY have two potential value : FIELD LOCAL (i.e cast <<(VariableBinding) binding>> is valid) + if ((bits & FIELD) != 0) { + if (!((FieldBinding) binding).isStatic()) { + //must check for the static status.... + if (indexOfFirstFieldBinding == 1) { + //the field is the first token of the qualified reference.... + if (scope.methodScope().isStatic) { + scope.problemReporter().staticFieldAccessToNonStaticVariable( + this, + (FieldBinding) binding); + return null; + } + } else { //accessing to a field using a type as "receiver" is allowed only with static field + scope.problemReporter().staticFieldAccessToNonStaticVariable( + this, + (FieldBinding) binding); + return null; + } + } + if (isFieldUseDeprecated((FieldBinding) binding, scope)) + scope.problemReporter().deprecatedField((FieldBinding) binding, this); + } + TypeBinding type = ((VariableBinding) binding).type; + int index = indexOfFirstFieldBinding; + int length = tokens.length; + if (index == length) { // restrictiveFlag == FIELD + constant = + FieldReference.getConstantFor((FieldBinding) binding, false, this, scope, index - 1); + return type; + } + // allocation of the fieldBindings array and its respective constants + int otherBindingsLength = length - index; + otherCodegenBindings = otherBindings = new FieldBinding[otherBindingsLength]; + otherDepths = new int[otherBindingsLength]; + + // fill the first constant (the one of the binding) + constant = + ((bits & FIELD) != 0) + ? FieldReference.getConstantFor((FieldBinding) binding, false, this, scope, index - 1) + : ((VariableBinding) binding).constant; + // save first depth, since will be updated by visibility checks of other bindings + int firstDepth = (bits & DepthMASK) >> DepthSHIFT; + // iteration on each field + while (index < length) { + char[] token = tokens[index]; + if (type == null) + return null; // could not resolve type prior to this point + + bits &= ~DepthMASK; // flush previous depth if any + FieldBinding field = scope.getField(type, token, this); + int place = index - indexOfFirstFieldBinding; + otherBindings[place] = field; + otherDepths[place] = (bits & DepthMASK) >> DepthSHIFT; + if (field.isValidBinding()) { + if (isFieldUseDeprecated(field, scope)) + scope.problemReporter().deprecatedField(field, this); + Constant someConstant = + FieldReference.getConstantFor(field, false, this, scope, place); + // constant propagation can only be performed as long as the previous one is a constant too. + if (constant != NotAConstant) { + constant = someConstant; + } + type = field.type; + index++; + } else { + constant = NotAConstant; //don't fill other constants slots... + scope.problemReporter().invalidField(this, field, index, type); + setDepth(firstDepth); + return null; + } + } + setDepth(firstDepth); + return (otherBindings[otherBindingsLength - 1]).type; + } + public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) { + //If inlinable field, forget the access emulation, the code gen will directly target it + if (((bits & DepthMASK) == 0) || (constant != NotAConstant)) { + return; + } + switch (bits & RestrictiveFlagMASK) { + case FIELD : + FieldBinding fieldBinding; + if ((fieldBinding = (FieldBinding) binding).isStatic() + || (fieldBinding.constant != NotAConstant)) + return; + ReferenceBinding compatibleType = currentScope.enclosingSourceType(); + // the declaringClass of the target binding must be compatible with the enclosing + // type at levels outside + for (int i = 0, depth = (bits & DepthMASK) >> DepthSHIFT; i < depth; i++) { + compatibleType = compatibleType.enclosingType(); + } + currentScope.emulateOuterAccess(compatibleType, false); + // request cascade of accesses + break; + case LOCAL : + currentScope.emulateOuterAccess((LocalVariableBinding) binding); + } + } + public void manageSyntheticReadAccessIfNecessary( + BlockScope currentScope, + FieldBinding fieldBinding, + TypeBinding lastReceiverType, + int index) { + // index == 0 denotes the first fieldBinding, index > 0 denotes one of the 'otherBindings' + if (fieldBinding.constant != NotAConstant) + return; + if (fieldBinding.isPrivate()) { // private access + if (fieldBinding.declaringClass != currentScope.enclosingSourceType()) { + if (syntheticReadAccessors == null) { + if (otherBindings == null) + syntheticReadAccessors = new SyntheticAccessMethodBinding[1]; + else + syntheticReadAccessors = + new SyntheticAccessMethodBinding[otherBindings.length + 1]; + } + syntheticReadAccessors[index] = ((SourceTypeBinding) fieldBinding.declaringClass).addSyntheticMethod(fieldBinding, true); + currentScope.problemReporter().needToEmulateFieldReadAccess(fieldBinding, this); + return; + } + } else if (fieldBinding.isProtected()){ + int depth = index == 0 ? (bits & DepthMASK) >> DepthSHIFT : otherDepths[index-1]; + // implicit protected access (only for first one) + if (depth > 0 && (fieldBinding.declaringClass.getPackage() + != currentScope.enclosingSourceType().getPackage())) { + if (syntheticReadAccessors == null) { + if (otherBindings == null) + syntheticReadAccessors = new SyntheticAccessMethodBinding[1]; + else + syntheticReadAccessors = + new SyntheticAccessMethodBinding[otherBindings.length + 1]; + } + syntheticReadAccessors[index] = + ((SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(depth)) + .addSyntheticMethod(fieldBinding, true); + currentScope.problemReporter().needToEmulateFieldReadAccess(fieldBinding, this); + return; + } + } + // if the binding declaring class is not visible, need special action + // for runtime compatibility on 1.2 VMs : change the declaring class of the binding + // NOTE: from 1.4 on, field's declaring class is touched if any different from receiver type + if (fieldBinding.declaringClass != lastReceiverType + && !lastReceiverType.isArrayType() + && fieldBinding.declaringClass != null + && fieldBinding.constant == NotAConstant + && ((currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4 + && (index > 0 || indexOfFirstFieldBinding > 1 || !fieldBinding.isStatic()) + && fieldBinding.declaringClass.id != T_Object) + || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){ + if (index == 0){ + this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType); + } else { + if (this.otherCodegenBindings == this.otherBindings){ + int l = this.otherBindings.length; + System.arraycopy(this.otherBindings, 0, this.otherCodegenBindings = new FieldBinding[l], 0, l); + } + this.otherCodegenBindings[index-1] = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType); + } + } + } + /* + * No need to emulate access to protected fields since not implicitly accessed + */ + public void manageSyntheticWriteAccessIfNecessary( + BlockScope currentScope, + FieldBinding fieldBinding, + TypeBinding lastReceiverType) { + if (fieldBinding.isPrivate()) { + if (fieldBinding.declaringClass != currentScope.enclosingSourceType()) { + syntheticWriteAccessor = ((SourceTypeBinding) fieldBinding.declaringClass) + .addSyntheticMethod(fieldBinding, false); + currentScope.problemReporter().needToEmulateFieldWriteAccess(fieldBinding, this); + return; + } + } else if (fieldBinding.isProtected()){ + int depth = fieldBinding == binding ? (bits & DepthMASK) >> DepthSHIFT : otherDepths[otherDepths.length-1]; + if (depth > 0 && (fieldBinding.declaringClass.getPackage() + != currentScope.enclosingSourceType().getPackage())) { + syntheticWriteAccessor = ((SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(depth)) + .addSyntheticMethod(fieldBinding, false); + currentScope.problemReporter().needToEmulateFieldWriteAccess(fieldBinding, this); + return; + } + } + // if the binding declaring class is not visible, need special action + // for runtime compatibility on 1.2 VMs : change the declaring class of the binding + // NOTE: from 1.4 on, field's declaring class is touched if any different from receiver type + if (fieldBinding.declaringClass != lastReceiverType + && !lastReceiverType.isArrayType() + && fieldBinding.declaringClass != null + && fieldBinding.constant == NotAConstant + && ((currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4 + && (fieldBinding != binding || indexOfFirstFieldBinding > 1 || !fieldBinding.isStatic()) + && fieldBinding.declaringClass.id != T_Object) + || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){ + if (fieldBinding == binding){ + this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType); + } else { + if (this.otherCodegenBindings == this.otherBindings){ + int l = this.otherBindings.length; + System.arraycopy(this.otherBindings, 0, this.otherCodegenBindings = new FieldBinding[l], 0, l); + } + this.otherCodegenBindings[this.otherCodegenBindings.length-1] = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType); + } + } + + } + /** + * Normal field binding did not work, try to bind to a field of the delegate receiver. + */ + public TypeBinding reportError(BlockScope scope) { + if (binding instanceof ProblemFieldBinding) { + scope.problemReporter().invalidField(this, (FieldBinding) binding); + } else if (binding instanceof ProblemReferenceBinding) { + scope.problemReporter().invalidType(this, (TypeBinding) binding); + } else { + scope.problemReporter().unresolvableReference(this, binding); + } + return null; + } + public TypeBinding resolveType(BlockScope scope) { + // field and/or local are done before type lookups + // the only available value for the restrictiveFlag BEFORE + // the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField + this.actualReceiverType = this.receiverType = scope.enclosingSourceType(); + constant = Constant.NotAConstant; + if ((this.codegenBinding = this.binding = scope.getBinding(tokens, bits & RestrictiveFlagMASK, this)) + .isValidBinding()) { + switch (bits & RestrictiveFlagMASK) { + case VARIABLE : //============only variable=========== + case TYPE | VARIABLE : + if (binding instanceof LocalVariableBinding) { + if (!((LocalVariableBinding) binding).isFinal() && ((bits & DepthMASK) != 0)) + scope.problemReporter().cannotReferToNonFinalOuterLocal( + (LocalVariableBinding) binding, + this); + bits &= ~RestrictiveFlagMASK; // clear bits + bits |= LOCAL; + return getOtherFieldBindings(scope); + } + if (binding instanceof FieldBinding) { + // check for forward references + FieldBinding fieldBinding = (FieldBinding) binding; + MethodScope methodScope = scope.methodScope(); + if (methodScope.enclosingSourceType() == fieldBinding.declaringClass + && methodScope.fieldDeclarationIndex != methodScope.NotInFieldDecl + && fieldBinding.id >= methodScope.fieldDeclarationIndex) { + if ((!fieldBinding.isStatic() || methodScope.isStatic) + && this.indexOfFirstFieldBinding == 1) + scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType()); + } + bits &= ~RestrictiveFlagMASK; // clear bits + bits |= FIELD; + return getOtherFieldBindings(scope); + } + // thus it was a type + bits &= ~RestrictiveFlagMASK; // clear bits + bits |= TYPE; + case TYPE : //=============only type ============== + //deprecated test + if (isTypeUseDeprecated((TypeBinding) binding, scope)) + scope.problemReporter().deprecatedType((TypeBinding) binding, this); + return (TypeBinding) binding; + } + } + //========error cases=============== + return this.reportError(scope); + } + public void setFieldIndex(int index) { + this.indexOfFirstFieldBinding = index; + } + public String toStringExpression() { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < tokens.length; i++) { + buffer.append(tokens[i]); + if (i < (tokens.length - 1)) { + buffer.append("."); //$NON-NLS-1$ + } + } + return buffer.toString(); + } + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } + public String unboundReferenceErrorName() { + return new String(tokens[0]); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/QualifiedSuperReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/QualifiedSuperReference.java new file mode 100644 index 0000000..91cf364 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/QualifiedSuperReference.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class QualifiedSuperReference extends QualifiedThisReference { + + public QualifiedSuperReference(TypeReference name, int pos, int sourceEnd) { + super(name, pos, sourceEnd); + } + + public boolean isSuper() { + + return true; + } + + public boolean isThis() { + + return false; + } + + public TypeBinding resolveType(BlockScope scope) { + + super.resolveType(scope); + if (currentCompatibleType == null) + return null; // error case + + if (scope.isJavaLangObject(currentCompatibleType)) { + scope.problemReporter().cannotUseSuperInJavaLangObject(this); + return null; + } + return currentCompatibleType.superclass(); + } + + public String toStringExpression() { + + return qualification.toString(0) + ".super"; //$NON-NLS-1$ + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + qualification.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/QualifiedThisReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/QualifiedThisReference.java new file mode 100644 index 0000000..e19c352 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/QualifiedThisReference.java @@ -0,0 +1,176 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class QualifiedThisReference extends ThisReference { + + public TypeReference qualification; + ReferenceBinding currentCompatibleType; + + public QualifiedThisReference(TypeReference name, int pos, int sourceEnd) { + + qualification = name; + this.sourceEnd = sourceEnd; + this.sourceStart = name.sourceStart; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + manageEnclosingInstanceAccessIfNecessary(currentScope); + return flowInfo; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo, + boolean valueRequired) { + + if (valueRequired) { + manageEnclosingInstanceAccessIfNecessary(currentScope); + } + return flowInfo; + } + + protected boolean checkAccess( + MethodScope methodScope, + TypeBinding targetType) { + + // this/super cannot be used in constructor call + if (methodScope.isConstructorCall) { + methodScope.problemReporter().fieldsOrThisBeforeConstructorInvocation(this); + return false; + } + + // static may not refer to this/super + if (methodScope.isStatic) { + methodScope.problemReporter().incorrectEnclosingInstanceReference( + this, + targetType); + return false; + } + return true; + } + + /** + * Code generation for QualifiedThisReference + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + if (valueRequired) { + if ((bits & DepthMASK) != 0) { + Object[] emulationPath = + currentScope.getExactEmulationPath(currentCompatibleType); + if (emulationPath == null) { + // internal error, per construction we should have found it + currentScope.problemReporter().needImplementation(); + } else { + codeStream.generateOuterAccess(emulationPath, this, currentScope); + } + } else { + // nothing particular after all + codeStream.aload_0(); + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) { + + currentScope.emulateOuterAccess( + (SourceTypeBinding) currentCompatibleType, + false); + // request cascade of accesses + } + + public TypeBinding resolveType(BlockScope scope) { + + constant = NotAConstant; + TypeBinding qualificationTb = qualification.resolveType(scope); + if (qualificationTb == null) + return null; + + // the qualification MUST exactly match some enclosing type name + // Its possible to qualify 'this' by the name of the current class + int depth = 0; + currentCompatibleType = scope.referenceType().binding; + while (currentCompatibleType != null + && currentCompatibleType != qualificationTb) { + depth++; + currentCompatibleType = + currentCompatibleType.isStatic() ? null : currentCompatibleType.enclosingType(); + } + bits &= ~DepthMASK; // flush previous depth if any + bits |= (depth & 0xFF) << DepthSHIFT; // encoded depth into 8 bits + + if (currentCompatibleType == null) { + scope.problemReporter().incorrectEnclosingInstanceReference( + this, + qualificationTb); + return null; + } + + // Ensure one cannot write code like: B() { super(B.this); } + if (depth == 0) { + if (!checkAccess(scope.methodScope(), qualificationTb)) + return null; + } else { + // Could also be targeting an enclosing instance inside a super constructor invocation + // class X { + // public X(int i) { + // this(new Object() { Object obj = X.this; }); + // } + // } + + MethodScope methodScope = scope.methodScope(); + while (methodScope != null) { + if (methodScope.enclosingSourceType() == currentCompatibleType) { + if (!this.checkAccess(methodScope, qualificationTb)) + return null; + break; + } + methodScope = methodScope.parent.methodScope(); + } + } + return qualificationTb; + } + + public String toStringExpression() { + + return qualification.toString(0) + ".this"; //$NON-NLS-1$ + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + qualification.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/QualifiedTypeReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/QualifiedTypeReference.java new file mode 100644 index 0000000..3987a6c --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/QualifiedTypeReference.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class QualifiedTypeReference extends TypeReference { + public char[][] tokens; + public long[] sourcePositions; +public QualifiedTypeReference(char[][] sources , long[] poss) { + tokens = sources ; + sourcePositions = poss ; + sourceStart = (int) (sourcePositions[0]>>>32) ; + sourceEnd = (int)(sourcePositions[sourcePositions.length-1] & 0x00000000FFFFFFFFL ) ; +} +public QualifiedTypeReference(char[][] sources , TypeBinding tb , long[] poss) { + this(sources,poss); + binding = tb; +} +public TypeReference copyDims(int dim){ + //return a type reference copy of me with some dimensions + //warning : the new type ref has a null binding + + return new ArrayQualifiedTypeReference(tokens,null,dim,sourcePositions) ; +} +public TypeBinding getTypeBinding(Scope scope) { + if (binding != null) + return binding; + return scope.getType(tokens); +} +public char[][] getTypeName(){ + + return tokens; +} +public String toStringExpression(int tab) { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < tokens.length; i++) { + buffer.append(tokens[i]); + if (i < (tokens.length - 1)) { + buffer.append("."); //$NON-NLS-1$ + } + } + return buffer.toString(); +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, ClassScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Reference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Reference.java new file mode 100644 index 0000000..dc7c3a5 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Reference.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; +import net.sourceforge.phpdt.internal.compiler.util.Util; + +public abstract class Reference extends Expression { +/** + * BaseLevelReference constructor comment. + */ +public Reference() { + super(); +} +public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { + throw new ShouldNotImplement(Util.bind("ast.variableShouldProvide")); //$NON-NLS-1$ +} +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + return flowInfo; +} +public FieldBinding fieldBinding() { + //this method should be sent one FIELD-tagged references + // (ref.bits & BindingIds.FIELD != 0)() + return null ; +} +public void fieldStore(CodeStream codeStream, FieldBinding fieldBinding, MethodBinding syntheticWriteAccessor, boolean valueRequired) { + + if (fieldBinding.isStatic()) { + if (valueRequired) { + if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) { + codeStream.dup2(); + } else { + codeStream.dup(); + } + } + if (syntheticWriteAccessor == null) { + codeStream.putstatic(fieldBinding); + } else { + codeStream.invokestatic(syntheticWriteAccessor); + } + } else { // Stack: [owner][new field value] ---> [new field value][owner][new field value] + if (valueRequired) { + if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) { + codeStream.dup2_x1(); + } else { + codeStream.dup_x1(); + } + } + if (syntheticWriteAccessor == null) { + codeStream.putfield(fieldBinding); + } else { + codeStream.invokestatic(syntheticWriteAccessor); + } + } +} +public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) { + throw new ShouldNotImplement(Util.bind("ast.compoundPreShouldProvide")); //$NON-NLS-1$ +} +public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { + throw new ShouldNotImplement(Util.bind("ast.compoundVariableShouldProvide")); //$NON-NLS-1$ +} +public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) { + throw new ShouldNotImplement(Util.bind("ast.postIncrShouldProvide")); //$NON-NLS-1$ +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ReturnStatement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ReturnStatement.java new file mode 100644 index 0000000..8da806d --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ReturnStatement.java @@ -0,0 +1,249 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class ReturnStatement extends Statement { + public Expression expression; + + public TypeBinding expressionType; + public boolean isSynchronized; + public AstNode[] subroutines; + public LocalVariableBinding saveValueVariable; + +public ReturnStatement(Expression expr, int s, int e ) { + sourceStart = s; + sourceEnd = e; + expression = expr ; +} +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { // here requires to generate a sequence of finally blocks invocations depending corresponding + // to each of the traversed try statements, so that execution will terminate properly. + + // lookup the label, this should answer the returnContext + + if (expression != null) { + flowInfo = expression.analyseCode(currentScope, flowContext, flowInfo); + } + // compute the return sequence (running the finally blocks) + FlowContext traversedContext = flowContext; + int subIndex = 0, maxSub = 5; + boolean saveValueNeeded = false; + boolean hasValueToSave = expression != null && expression.constant == NotAConstant; + while (true) { + AstNode sub; + if ((sub = traversedContext.subRoutine()) != null) { + if (this.subroutines == null){ + this.subroutines = new AstNode[maxSub]; + } + if (subIndex == maxSub) { + System.arraycopy(this.subroutines, 0, (this.subroutines = new AstNode[maxSub *= 2]), 0, subIndex); // grow + } + this.subroutines[subIndex++] = sub; + if (sub.cannotReturn()) { + saveValueNeeded = false; + break; + } + } + AstNode node; + + if ((node = traversedContext.associatedNode) instanceof SynchronizedStatement) { + isSynchronized = true; + + } else if (node instanceof TryStatement && hasValueToSave) { + if (this.saveValueVariable == null){ // closest subroutine secret variable is used + prepareSaveValueLocation((TryStatement)node); + } + saveValueNeeded = true; + + } else if (traversedContext instanceof InitializationFlowContext) { + currentScope.problemReporter().cannotReturnInInitializer(this); + return FlowInfo.DeadEnd; + } + + // remember the initialization at this + // point for dealing with blank final variables. + traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); + + FlowContext parentContext; + if ((parentContext = traversedContext.parent) == null) { // top-context + break; + } else { + traversedContext = parentContext; + } + } + // resize subroutines + if ((subroutines != null) && (subIndex != maxSub)) { + System.arraycopy(subroutines, 0, (subroutines = new AstNode[subIndex]), 0, subIndex); + } + + // secret local variable for return value (note that this can only occur in a real method) + if (saveValueNeeded) { + if (this.saveValueVariable != null) { + this.saveValueVariable.used = true; + } + } else { + this.saveValueVariable = null; + if ((!isSynchronized) && (expressionType == BooleanBinding)) { + this.expression.bits |= ValueForReturnMASK; + } + } + return FlowInfo.DeadEnd; +} + +/** + * Retrun statement code generation + * + * generate the finallyInvocationSequence. + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream) { + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + // generate the expression + if ((expression != null) && (expression.constant == NotAConstant)) { + expression.generateCode(currentScope, codeStream, needValue()); // no value needed if non-returning subroutine + generateStoreSaveValueIfNecessary(currentScope, codeStream); + } + + // generation of code responsible for invoking the finally blocks in sequence + if (subroutines != null) { + for (int i = 0, max = subroutines.length; i < max; i++) { + AstNode sub; + if ((sub = subroutines[i]) instanceof SynchronizedStatement) { + codeStream.load(((SynchronizedStatement) sub).synchroVariable); + codeStream.monitorexit(); + } else { + TryStatement trySub = (TryStatement) sub; + if (trySub.subRoutineCannotReturn) { + codeStream.goto_(trySub.subRoutineStartLabel); + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } else { + codeStream.jsr(trySub.subRoutineStartLabel); + } + } + } + } + if (saveValueVariable != null) codeStream.load(saveValueVariable); + + if ((expression != null) && (expression.constant != NotAConstant)) { + codeStream.generateConstant(expression.constant, expression.implicitConversion); + generateStoreSaveValueIfNecessary(currentScope, codeStream); + } + // output the suitable return bytecode or wrap the value inside a descriptor for doits + this.generateReturnBytecode(currentScope, codeStream); + + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +/** + * Dump the suitable return bytecode for a return statement + * + */ +public void generateReturnBytecode(BlockScope currentScope, CodeStream codeStream) { + + if (expression == null) { + codeStream.return_(); + } else { + switch (expression.implicitConversion >> 4) { + case T_boolean : + case T_int : + codeStream.ireturn(); + break; + case T_float : + codeStream.freturn(); + break; + case T_long : + codeStream.lreturn(); + break; + case T_double : + codeStream.dreturn(); + break; + default : + codeStream.areturn(); + } + } +} +public void generateStoreSaveValueIfNecessary(BlockScope currentScope, CodeStream codeStream){ + + if (saveValueVariable != null) codeStream.store(saveValueVariable, false); +} +public boolean needValue(){ + return (subroutines == null) || (saveValueVariable != null) || isSynchronized; +} +public void prepareSaveValueLocation(TryStatement targetTryStatement){ + + this.saveValueVariable = targetTryStatement.secretReturnValue; +} +public void resolve(BlockScope scope) { + MethodScope methodScope = scope.methodScope(); + MethodBinding methodBinding; + TypeBinding methodType = + (methodScope.referenceContext instanceof AbstractMethodDeclaration) + ? ((methodBinding = ((AbstractMethodDeclaration) methodScope.referenceContext).binding) == null + ? null + : methodBinding.returnType) + : VoidBinding; + if (methodType == VoidBinding) { + // the expression should be null + if (expression == null) + return; + if ((expressionType = expression.resolveType(scope)) != null) + scope.problemReporter().attemptToReturnNonVoidExpression(this, expressionType); + return; + } + if (expression == null) { + if (methodType != null) scope.problemReporter().shouldReturn(methodType, this); + return; + } + if ((expressionType = expression.resolveType(scope)) == null) + return; + + if (methodType != null && expression.isConstantValueOfTypeAssignableToType(expressionType, methodType)) { + // dealing with constant + expression.implicitWidening(methodType, expressionType); + return; + } + if (expressionType == VoidBinding) { + scope.problemReporter().attemptToReturnVoidValue(this); + return; + } + if (methodType != null && scope.areTypesCompatible(expressionType, methodType)) { + expression.implicitWidening(methodType, expressionType); + return; + } + if (methodType != null){ + scope.problemReporter().typeMismatchErrorActualTypeExpectedType(expression, expressionType, methodType); + } +} +public String toString(int tab){ + + String s = tabString(tab) ; + s = s + "return "; //$NON-NLS-1$ + if (expression != null ) + s = s + expression.toStringExpression() ; + return s; +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + if (visitor.visit(this, scope)) { + if (expression != null) + expression.traverse(visitor, scope); + } + visitor.endVisit(this, scope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/SingleNameReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/SingleNameReference.java new file mode 100644 index 0000000..fee9115 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/SingleNameReference.java @@ -0,0 +1,693 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class SingleNameReference extends NameReference implements OperatorIds { + public char[] token; + + public MethodBinding[] syntheticAccessors; // [0]=read accessor [1]=write accessor + public static final int READ = 0; + public static final int WRITE = 1; + +public SingleNameReference(char[] source, long pos) { + super(); + token = source; + sourceStart = (int) (pos >>> 32); + sourceEnd = (int) pos; +} +public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { + + // compound assignment extra work + if (isCompound) { // check the variable part is initialized if blank final + switch (bits & RestrictiveFlagMASK) { + case FIELD : // reading a field + FieldBinding fieldBinding; + if ((fieldBinding = (FieldBinding) binding).isFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) { + if (!flowInfo.isDefinitelyAssigned(fieldBinding)) { + currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); + // we could improve error msg here telling "cannot use compound assignment on final blank field" + } + } + manageSyntheticReadAccessIfNecessary(currentScope); + break; + case LOCAL : // reading a local variable + // check if assigning a final blank field + LocalVariableBinding localBinding; + if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) { + currentScope.problemReporter().uninitializedLocalVariable(localBinding, this); + // we could improve error msg here telling "cannot use compound assignment on final local variable" + } + if (!flowInfo.isFakeReachable()) localBinding.used = true; + } + } + if (assignment.expression != null) { + flowInfo = assignment.expression.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + } + switch (bits & RestrictiveFlagMASK) { + case FIELD : // assigning to a field + manageSyntheticWriteAccessIfNecessary(currentScope); + + // check if assigning a final field + FieldBinding fieldBinding; + if ((fieldBinding = (FieldBinding) binding).isFinal()) { + // inside a context where allowed + if (currentScope.allowBlankFinalFieldAssignment(fieldBinding)) { + if (flowInfo.isPotentiallyAssigned(fieldBinding)) { + currentScope.problemReporter().duplicateInitializationOfBlankFinalField(fieldBinding, this); + } + flowInfo.markAsDefinitelyAssigned(fieldBinding); + flowContext.recordSettingFinal(fieldBinding, this); + } else { + currentScope.problemReporter().cannotAssignToFinalField(fieldBinding, this); + } + } + break; + case LOCAL : // assigning to a local variable + LocalVariableBinding localBinding = (LocalVariableBinding) binding; + if (!flowInfo.isDefinitelyAssigned(localBinding)){// for local variable debug attributes + bits |= FirstAssignmentToLocalMASK; + } else { + bits &= ~FirstAssignmentToLocalMASK; + } + if (localBinding.isFinal()) { + if ((bits & DepthMASK) == 0) { + if (flowInfo.isPotentiallyAssigned(localBinding)) { + currentScope.problemReporter().duplicateInitializationOfFinalLocal(localBinding, this); + } + flowContext.recordSettingFinal(localBinding, this); + } else { + currentScope.problemReporter().cannotAssignToFinalOuterLocal(localBinding, this); + } + } + flowInfo.markAsDefinitelyAssigned(localBinding); + } + manageEnclosingInstanceAccessIfNecessary(currentScope); + return flowInfo; +} +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + return analyseCode(currentScope, flowContext, flowInfo, true); +} +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { + + switch (bits & RestrictiveFlagMASK) { + case FIELD : // reading a field + if (valueRequired) { + manageSyntheticReadAccessIfNecessary(currentScope); + } + // check if reading a final blank field + FieldBinding fieldBinding; + if ((fieldBinding = (FieldBinding) binding).isFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) { + if (!flowInfo.isDefinitelyAssigned(fieldBinding)) { + currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); + } + } + break; + case LOCAL : // reading a local variable + LocalVariableBinding localBinding; + if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) { + currentScope.problemReporter().uninitializedLocalVariable(localBinding, this); + } + if (!flowInfo.isFakeReachable()) localBinding.used = true; + } + if (valueRequired) { + manageEnclosingInstanceAccessIfNecessary(currentScope); + } + return flowInfo; +} +public TypeBinding checkFieldAccess(BlockScope scope) { + + FieldBinding fieldBinding = (FieldBinding) binding; + + bits &= ~RestrictiveFlagMASK; // clear bits + bits |= FIELD; + if (!((FieldBinding) binding).isStatic()) { + // must check for the static status.... + if (scope.methodScope().isStatic) { + scope.problemReporter().staticFieldAccessToNonStaticVariable( + this, + fieldBinding); + constant = NotAConstant; + return null; + } + } + constant = FieldReference.getConstantFor(fieldBinding, true, this, scope, 0); + if (isFieldUseDeprecated(fieldBinding, scope)) + scope.problemReporter().deprecatedField(fieldBinding, this); + + //=============================================== + //cycle are forbidden ONLY within the same class...why ?????? (poor javac....) + //Cycle can be done using cross class ref but not direct into a same class reference ???? + //class A { static int k = B.k+1;} + //class B { static int k = A.k+2;} + //The k-cycle in this example is valid. + + //class C { static int k = k + 1 ;} + //here it is forbidden ! ???? + //but the next one is valid !!! + //class C { static int k = C.k + 1;} + + //notice that the next one is also valid ?!?! + //class A { static int k = foo().k+1 ; static A foo(){return new A();}} + + //for all these reasons, the next piece of code is only here and not + //commun for all FieldRef and QualifiedNameRef....(i.e. in the getField(..) API..... + + //instance field may refer to forward static field, like in + //int i = staticI; + //static int staticI = 2 ; + + MethodScope ms = scope.methodScope(); + if (ms.enclosingSourceType() == fieldBinding.declaringClass + && ms.fieldDeclarationIndex != ms.NotInFieldDecl + && fieldBinding.id >= ms.fieldDeclarationIndex) { + //if the field is static and ms is not .... then it is valid + if (!fieldBinding.isStatic() || ms.isStatic) + scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType()); + } + //==================================================== + + return fieldBinding.type; + +} +public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) { + + // optimizing assignment like: i = i + 1 or i = 1 + i + if (assignment.expression.isCompactableOperation()) { + BinaryExpression operation = (BinaryExpression) assignment.expression; + SingleNameReference variableReference; + if ((operation.left instanceof SingleNameReference) && ((variableReference = (SingleNameReference) operation.left).binding == binding)) { + // i = i + value, then use the variable on the right hand side, since it has the correct implicit conversion + variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.right, (operation.bits & OperatorMASK) >> OperatorSHIFT, operation.left.implicitConversion /*should be equivalent to no conversion*/, valueRequired); + return; + } + int operator = (operation.bits & OperatorMASK) >> OperatorSHIFT; + if ((operation.right instanceof SingleNameReference) + && ((operator == PLUS) || (operator == MULTIPLY)) // only commutative operations + && ((variableReference = (SingleNameReference) operation.right).binding == binding) + && (operation.left.constant != NotAConstant) // exclude non constant expressions, since could have side-effect + && ((operation.left.implicitConversion >> 4) != T_String) // exclude string concatenation which would occur backwards + && ((operation.right.implicitConversion >> 4) != T_String)) { // exclude string concatenation which would occur backwards + // i = value + i, then use the variable on the right hand side, since it has the correct implicit conversion + variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.left, operator, operation.right.implicitConversion /*should be equivalent to no conversion*/, valueRequired); + return; + } + } + switch (bits & RestrictiveFlagMASK) { + case FIELD : // assigning to a field + FieldBinding fieldBinding; + if (!(fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) { // need a receiver? + if ((bits & DepthMASK) != 0) { + Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)); + if (emulationPath == null) { + // internal error, per construction we should have found it + currentScope.problemReporter().needImplementation(); + } else { + codeStream.generateOuterAccess(emulationPath, this, currentScope); + } + } else { + this.generateReceiver(codeStream); + } + } + assignment.expression.generateCode(currentScope, codeStream, true); + fieldStore(codeStream, fieldBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], valueRequired); + if (valueRequired) { + codeStream.generateImplicitConversion(assignment.implicitConversion); + } + return; + case LOCAL : // assigning to a local variable + LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; + if (localBinding.resolvedPosition != -1) { + assignment.expression.generateCode(currentScope, codeStream, true); + } else { + if (assignment.expression.constant != NotAConstant) { + // assigning an unused local to a constant value = no actual assignment is necessary + if (valueRequired) { + codeStream.generateConstant(assignment.expression.constant, assignment.implicitConversion); + } + } else { + assignment.expression.generateCode(currentScope, codeStream, true); + /* Even though the value may not be required, we force it to be produced, and discard it later + on if it was actually not necessary, so as to provide the same behavior as JDK1.2beta3. */ + if (valueRequired) { + codeStream.generateImplicitConversion(assignment.implicitConversion); // implicit conversion + } else { + if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) { + codeStream.pop2(); + } else { + codeStream.pop(); + } + } + } + return; + } + // normal local assignment (since cannot store in outer local which are final locations) + codeStream.store(localBinding, valueRequired); + if ((bits & FirstAssignmentToLocalMASK) != 0) { // for local variable debug attributes + localBinding.recordInitializationStartPC(codeStream.position); + } + // implicit conversion + if (valueRequired) { + codeStream.generateImplicitConversion(assignment.implicitConversion); + } + } +} +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + int pc = codeStream.position; + if (constant != NotAConstant) { + if (valueRequired) { + codeStream.generateConstant(constant, implicitConversion); + } + } else { + switch (bits & RestrictiveFlagMASK) { + case FIELD : // reading a field + FieldBinding fieldBinding; + if (valueRequired) { + if ((fieldBinding = (FieldBinding) this.codegenBinding).constant == NotAConstant) { // directly use inlined value for constant fields + boolean isStatic; + if (!(isStatic = fieldBinding.isStatic())) { + if ((bits & DepthMASK) != 0) { + Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)); + if (emulationPath == null) { + // internal error, per construction we should have found it + currentScope.problemReporter().needImplementation(); + } else { + codeStream.generateOuterAccess(emulationPath, this, currentScope); + } + } else { + generateReceiver(codeStream); + } + } + // managing private access + if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { + if (isStatic) { + codeStream.getstatic(fieldBinding); + } else { + codeStream.getfield(fieldBinding); + } + } else { + codeStream.invokestatic(syntheticAccessors[READ]); + } + codeStream.generateImplicitConversion(implicitConversion); + } else { // directly use the inlined value + codeStream.generateConstant(fieldBinding.constant, implicitConversion); + } + } + break; + case LOCAL : // reading a local + LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; + if (valueRequired) { + // outer local? + if ((bits & DepthMASK) != 0) { + // outer local can be reached either through a synthetic arg or a synthetic field + VariableBinding[] path = currentScope.getEmulationPath(localBinding); + if (path == null) { + // emulation was not possible (should not happen per construction) + currentScope.problemReporter().needImplementation(); + } else { + codeStream.generateOuterAccess(path, this, currentScope); + } + } else { + // regular local variable read + codeStream.load(localBinding); + } + codeStream.generateImplicitConversion(implicitConversion); + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +/* + * Regular API for compound assignment, relies on the fact that there is only one reference to the + * variable, which carries both synthetic read/write accessors. + * The APIs with an extra argument is used whenever there are two references to the same variable which + * are optimized in one access: e.g "a = a + 1" optimized into "a++". + */ +public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { + + this.generateCompoundAssignment( + currentScope, + codeStream, + syntheticAccessors == null ? null : syntheticAccessors[WRITE], + expression, + operator, + assignmentImplicitConversion, + valueRequired); +} +/* + * The APIs with an extra argument is used whenever there are two references to the same variable which + * are optimized in one access: e.g "a = a + 1" optimized into "a++". + */ +public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, MethodBinding writeAccessor, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { + switch (bits & RestrictiveFlagMASK) { + case FIELD : // assigning to a field + FieldBinding fieldBinding; + if ((fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) { + if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { + codeStream.getstatic(fieldBinding); + } else { + codeStream.invokestatic(syntheticAccessors[READ]); + } + } else { + if ((bits & DepthMASK) != 0) { + Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)); + if (emulationPath == null) { + // internal error, per construction we should have found it + currentScope.problemReporter().needImplementation(); + } else { + codeStream.generateOuterAccess(emulationPath, this, currentScope); + } + } else { + codeStream.aload_0(); + } + codeStream.dup(); + if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { + codeStream.getfield(fieldBinding); + } else { + codeStream.invokestatic(syntheticAccessors[READ]); + } + } + break; + case LOCAL : // assigning to a local variable (cannot assign to outer local) + LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; + Constant assignConstant; + int increment; + // using incr bytecode if possible + switch (localBinding.type.id) { + case T_String : + codeStream.generateStringAppend(currentScope, this, expression); + if (valueRequired) { + codeStream.dup(); + } + codeStream.store(localBinding, false); + return; + case T_int : + if (((assignConstant = expression.constant) != NotAConstant) + && (assignConstant.typeID() != T_float) // only for integral types + && (assignConstant.typeID() != T_double) + && ((increment = assignConstant.intValue()) == (short) increment)) { // 16 bits value + switch (operator) { + case PLUS : + codeStream.iinc(localBinding.resolvedPosition, increment); + if (valueRequired) { + codeStream.load(localBinding); + } + return; + case MINUS : + codeStream.iinc(localBinding.resolvedPosition, -increment); + if (valueRequired) { + codeStream.load(localBinding); + } + return; + } + } + default : + codeStream.load(localBinding); + } + } + // perform the actual compound operation + int operationTypeID; + if ((operationTypeID = implicitConversion >> 4) == T_String || operationTypeID == T_Object) { + // we enter here if the single name reference is a field of type java.lang.String or if the type of the + // operation is java.lang.Object + // For example: o = o + ""; // where the compiled type of o is java.lang.Object. + codeStream.generateStringAppend(currentScope, null, expression); + } else { + // promote the array reference to the suitable operation type + codeStream.generateImplicitConversion(implicitConversion); + // generate the increment value (will by itself be promoted to the operation value) + if (expression == IntLiteral.One){ // prefix operation + codeStream.generateConstant(expression.constant, implicitConversion); + } else { + expression.generateCode(currentScope, codeStream, true); + } + // perform the operation + codeStream.sendOperator(operator, operationTypeID); + // cast the value back to the array reference type + codeStream.generateImplicitConversion(assignmentImplicitConversion); + } + // store the result back into the variable + switch (bits & RestrictiveFlagMASK) { + case FIELD : // assigning to a field + fieldStore(codeStream, (FieldBinding) this.codegenBinding, writeAccessor, valueRequired); + return; + case LOCAL : // assigning to a local variable + LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; + if (valueRequired) { + if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) { + codeStream.dup2(); + } else { + codeStream.dup(); + } + } + codeStream.store(localBinding, false); + } +} +public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) { + switch (bits & RestrictiveFlagMASK) { + case FIELD : // assigning to a field + FieldBinding fieldBinding; + if ((fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) { + if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { + codeStream.getstatic(fieldBinding); + } else { + codeStream.invokestatic(syntheticAccessors[READ]); + } + } else { + if ((bits & DepthMASK) != 0) { + Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)); + if (emulationPath == null) { + // internal error, per construction we should have found it + currentScope.problemReporter().needImplementation(); + } else { + codeStream.generateOuterAccess(emulationPath, this, currentScope); + } + } else { + codeStream.aload_0(); + } + codeStream.dup(); + if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { + codeStream.getfield(fieldBinding); + } else { + codeStream.invokestatic(syntheticAccessors[READ]); + } + } + if (valueRequired) { + if (fieldBinding.isStatic()) { + if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) { + codeStream.dup2(); + } else { + codeStream.dup(); + } + } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value] + if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) { + codeStream.dup2_x1(); + } else { + codeStream.dup_x1(); + } + } + } + codeStream.generateConstant(postIncrement.expression.constant, implicitConversion); + codeStream.sendOperator(postIncrement.operator, fieldBinding.type.id); + codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion); + fieldStore(codeStream, fieldBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], false); + return; + case LOCAL : // assigning to a local variable + LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; + // using incr bytecode if possible + if (localBinding.type == IntBinding) { + if (valueRequired) { + codeStream.load(localBinding); + } + if (postIncrement.operator == PLUS) { + codeStream.iinc(localBinding.resolvedPosition, 1); + } else { + codeStream.iinc(localBinding.resolvedPosition, -1); + } + } else { + codeStream.load(localBinding); + if (valueRequired){ + if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) { + codeStream.dup2(); + } else { + codeStream.dup(); + } + } + codeStream.generateConstant(postIncrement.expression.constant, implicitConversion); + codeStream.sendOperator(postIncrement.operator, localBinding.type.id); + codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion); + + codeStream.store(localBinding, false); + } + } +} +public void generateReceiver(CodeStream codeStream) { + codeStream.aload_0(); +} +public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) { + + //If inlinable field, forget the access emulation, the code gen will directly target it + if (((bits & DepthMASK) == 0) || (constant != NotAConstant)) return; + + switch (bits & RestrictiveFlagMASK) { + case FIELD : + FieldBinding fieldBinding; + if ((fieldBinding = (FieldBinding)binding).isStatic() || (fieldBinding.constant != NotAConstant)) return; + ReferenceBinding compatibleType = currentScope.enclosingSourceType(); + // the declaringClass of the target binding must be compatible with the enclosing + // type at levels outside + for (int i = 0, depth = (bits & DepthMASK) >> DepthSHIFT; i < depth; i++) { + compatibleType = compatibleType.enclosingType(); + } + currentScope.emulateOuterAccess(compatibleType, false); // request cascade of accesses + break; + case LOCAL : + currentScope.emulateOuterAccess((LocalVariableBinding) binding); + } +} +public void manageSyntheticReadAccessIfNecessary(BlockScope currentScope) { + + //If inlinable field, forget the access emulation, the code gen will directly target it + if (constant != NotAConstant) + return; + + if ((bits & FIELD) != 0) { + FieldBinding fieldBinding = (FieldBinding) binding; + if (((bits & DepthMASK) != 0) + && (fieldBinding.isPrivate() // private access + || (fieldBinding.isProtected() // implicit protected access + && fieldBinding.declaringClass.getPackage() + != currentScope.enclosingSourceType().getPackage()))) { + if (syntheticAccessors == null) + syntheticAccessors = new MethodBinding[2]; + syntheticAccessors[READ] = + ((SourceTypeBinding)currentScope.enclosingSourceType(). + enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)). + addSyntheticMethod(fieldBinding, true); + currentScope.problemReporter().needToEmulateFieldReadAccess(fieldBinding, this); + return; + } + // if the binding declaring class is not visible, need special action + // for runtime compatibility on 1.2 VMs : change the declaring class of the binding + // NOTE: from 1.4 on, field's declaring class is touched if any different from receiver type + // and not from Object or implicit static field access. + if (fieldBinding.declaringClass != this.actualReceiverType + && !this.actualReceiverType.isArrayType() + && fieldBinding.declaringClass != null + && fieldBinding.constant == NotAConstant + && ((currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4 + && !fieldBinding.isStatic() + && fieldBinding.declaringClass.id != T_Object) // no change for Object fields (if there was any) + || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){ + this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)this.actualReceiverType); + } + } +} +public void manageSyntheticWriteAccessIfNecessary(BlockScope currentScope) { + + if ((bits & FIELD) != 0) { + FieldBinding fieldBinding = (FieldBinding) binding; + if (((bits & DepthMASK) != 0) + && (fieldBinding.isPrivate() // private access + || (fieldBinding.isProtected() // implicit protected access + && fieldBinding.declaringClass.getPackage() + != currentScope.enclosingSourceType().getPackage()))) { + if (syntheticAccessors == null) + syntheticAccessors = new MethodBinding[2]; + syntheticAccessors[WRITE] = + ((SourceTypeBinding)currentScope.enclosingSourceType(). + enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)). + addSyntheticMethod(fieldBinding, false); + currentScope.problemReporter().needToEmulateFieldWriteAccess(fieldBinding, this); + return; + } + // if the binding declaring class is not visible, need special action + // for runtime compatibility on 1.2 VMs : change the declaring class of the binding + // NOTE: from 1.4 on, field's declaring class is touched if any different from receiver type + // and not from Object or implicit static field access. + if (fieldBinding.declaringClass != this.actualReceiverType + && !this.actualReceiverType.isArrayType() + && fieldBinding.declaringClass != null + && fieldBinding.constant == NotAConstant + && ((currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4 + && !fieldBinding.isStatic() + && fieldBinding.declaringClass.id != T_Object) // no change for Object fields (if there was any) + || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){ + this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)this.actualReceiverType); + } + } +} +public TypeBinding reportError(BlockScope scope) { + //=====error cases======= + constant = Constant.NotAConstant; + if (binding instanceof ProblemFieldBinding) { + scope.problemReporter().invalidField(this, (FieldBinding) binding); + } else if (binding instanceof ProblemReferenceBinding) { + scope.problemReporter().invalidType(this, (TypeBinding) binding); + } else { + scope.problemReporter().unresolvableReference(this, binding); + } + return null; +} +public TypeBinding resolveType(BlockScope scope) { + // for code gen, harm the restrictiveFlag + + this.actualReceiverType = this.receiverType = scope.enclosingSourceType(); + + if ((this.codegenBinding = this.binding = scope.getBinding(token, bits & RestrictiveFlagMASK, this)).isValidBinding()) { + switch (bits & RestrictiveFlagMASK) { + case VARIABLE : // =========only variable============ + case VARIABLE | TYPE : //====both variable and type============ + if (binding instanceof VariableBinding) { + VariableBinding vb = (VariableBinding) binding; + if (binding instanceof LocalVariableBinding) { + bits &= ~RestrictiveFlagMASK; // clear bits + bits |= LOCAL; + constant = vb.constant; + if ((!vb.isFinal()) && ((bits & DepthMASK) != 0)) + scope.problemReporter().cannotReferToNonFinalOuterLocal((LocalVariableBinding)vb, this); + return vb.type; + } + // a field + return checkFieldAccess(scope); + } + + // thus it was a type + bits &= ~RestrictiveFlagMASK; // clear bits + bits |= TYPE; + case TYPE : //========only type============== + constant = Constant.NotAConstant; + //deprecated test + if (isTypeUseDeprecated((TypeBinding) binding, scope)) + scope.problemReporter().deprecatedType((TypeBinding) binding, this); + return (TypeBinding) binding; + } + } + + // error scenarii + return this.reportError(scope); +} +public String toStringExpression(){ + + return new String(token);} +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} +public String unboundReferenceErrorName(){ + + return new String(token);} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/SingleTypeReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/SingleTypeReference.java new file mode 100644 index 0000000..e8ac5c7 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/SingleTypeReference.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class SingleTypeReference extends TypeReference { + public char[] token; + + +public SingleTypeReference(char[] source, long pos) { + token = source; + sourceStart = (int) (pos>>>32) ; + sourceEnd = (int) (pos & 0x00000000FFFFFFFFL) ; + +} +public SingleTypeReference(char[] source ,TypeBinding tb, long pos) { + this(source, pos) ; + binding = tb ; +} +public TypeReference copyDims(int dim){ + //return a type reference copy of me with some dimensions + //warning : the new type ref has a null binding + + return new ArrayTypeReference(token,null,dim,(((long)sourceStart)<<32)+sourceEnd) ; +} +public TypeBinding getTypeBinding(Scope scope) { + if (binding != null) + return binding; + return scope.getType(token); +} +public char [][] getTypeName() { + return new char[][] { token }; +} +public TypeBinding resolveTypeEnclosing(BlockScope scope, ReferenceBinding enclosingType) { + ReferenceBinding memberTb = scope.getMemberType(token, enclosingType); + if (!memberTb.isValidBinding()) { + scope.problemReporter().invalidEnclosingType(this, memberTb, enclosingType); + return null; + } + if (isTypeUseDeprecated(memberTb, scope)) + scope.problemReporter().deprecatedType(memberTb, this); + return binding = memberTb; +} +public String toStringExpression(int tab){ + return new String(token) ; +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, ClassScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Statement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Statement.java new file mode 100644 index 0000000..3363777 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Statement.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; +import net.sourceforge.phpdt.internal.compiler.util.Util; + +public abstract class Statement extends AstNode { + + /** + * Statement constructor comment. + */ + public Statement() { + super(); + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + return flowInfo; + } + + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + throw new ShouldNotImplement(Util.bind("ast.missingStatement")); //$NON-NLS-1$ + } + + public boolean isEmptyBlock() { + return false; + } + + public boolean isValidJavaStatement() { + //the use of this method should be avoid in most cases + //and is here mostly for documentation purpose..... + //while the parser is responsable for creating + //welled formed expression statement, which results + //in the fact that java-non-semantic-expression-used-as-statement + //should not be parsable...thus not being built. + //It sounds like the java grammar as help the compiler job in removing + //-by construction- some statement that would have no effect.... + //(for example all expression that may do side-effects are valid statement + // -this is an appromative idea.....-) + + return true; + } + + public void resolve(BlockScope scope) { + } + + public Constant resolveCase( + BlockScope scope, + TypeBinding testType, + SwitchStatement switchStatement) { + // statement within a switch that are not case are treated as normal statement.... + + resolve(scope); + return null; + } + + public void resetStateForCodeGeneration() { + } + + /** + * INTERNAL USE ONLY. + * Do nothing by default. This is used to redirect inter-statements jumps. + */ + public void branchChainTo(Label label) { + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/StringLiteral.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/StringLiteral.java new file mode 100644 index 0000000..85bf3c3 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/StringLiteral.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream; +import net.sourceforge.phpdt.internal.compiler.impl.Constant; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; + +public class StringLiteral extends Literal { + char[] source; + +public StringLiteral(char[] token, int s, int e) { + this(s,e); + source = token; +} +public StringLiteral(int s, int e) { + super(s,e); +} +public void computeConstant() { + + constant = Constant.fromValue(String.valueOf(source));} +public ExtendedStringLiteral extendWith(CharLiteral lit){ + //add the lit source to mine, just as if it was mine + + return new ExtendedStringLiteral(this,lit); +} +public ExtendedStringLiteral extendWith(StringLiteral lit){ + //add the lit source to mine, just as if it was mine + + return new ExtendedStringLiteral(this,lit); +} +/** + * Code generation for string literal + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + int pc = codeStream.position; + if (valueRequired) + codeStream.ldc(constant.stringValue()); + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public TypeBinding literalType(BlockScope scope) { + return scope.getJavaLangString(); +} +/** + * source method comment. + */ +public char[] source() { + return source; +} +public String toStringExpression() { + + // handle some special char..... + StringBuffer result = new StringBuffer("\""); //$NON-NLS-1$ + for (int i = 0; i < source.length; i++) { + switch (source[i]) { + case '\b' : + result.append("\\b"); //$NON-NLS-1$ + break; + case '\t' : + result.append("\\t"); //$NON-NLS-1$ + break; + case '\n' : + result.append("\\n"); //$NON-NLS-1$ + break; + case '\f' : + result.append("\\f"); //$NON-NLS-1$ + break; + case '\r' : + result.append("\\r"); //$NON-NLS-1$ + break; + case '\"' : + result.append("\\\""); //$NON-NLS-1$ + break; + case '\'' : + result.append("\\'"); //$NON-NLS-1$ + break; + case '\\' : //take care not to display the escape as a potential real char + result.append("\\\\"); //$NON-NLS-1$ + break; + default : + result.append(source[i]); + } + } + result.append("\""); //$NON-NLS-1$ + return result.toString(); +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/SuperReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/SuperReference.java new file mode 100644 index 0000000..9c15de9 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/SuperReference.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; + +public class SuperReference extends ThisReference { + public static final SuperReference Super = new SuperReference(); + +/** + * SuperReference constructor comment. + */ +public SuperReference() { + super(); +} +public SuperReference(int pos, int sourceEnd) { + super(); + sourceStart = pos; + this.sourceEnd = sourceEnd; +} +public static ExplicitConstructorCall implicitSuperConstructorCall() { + return new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); +} +public boolean isSuper() { + + return true; +} +public boolean isThis() { + + return false ; +} +public TypeBinding resolveType(BlockScope scope) { + constant = NotAConstant; + if (!checkAccess(scope.methodScope())) + return null; + SourceTypeBinding enclosingTb = scope.enclosingSourceType(); + if (scope.isJavaLangObject(enclosingTb)) { + scope.problemReporter().cannotUseSuperInJavaLangObject(this); + return null; + } + return enclosingTb.superclass; +} +public String toStringExpression(){ + + return "super"; //$NON-NLS-1$ + +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope blockScope) { + visitor.visit(this, blockScope); + visitor.endVisit(this, blockScope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/SwitchStatement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/SwitchStatement.java new file mode 100644 index 0000000..b63fb4f --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/SwitchStatement.java @@ -0,0 +1,312 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class SwitchStatement extends Statement { + public Expression testExpression; + public Statement[] statements; + public BlockScope scope; + public int explicitDeclarations; + public Label breakLabel; + public Case[] cases; + public DefaultCase defaultCase; + public int caseCount = 0; + + // for local variables table attributes + int preSwitchInitStateIndex = -1; + int mergedInitStateIndex = -1; + /** + * SwitchStatement constructor comment. + */ + public SwitchStatement() { + super(); + } + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + flowInfo = testExpression.analyseCode(currentScope, flowContext, flowInfo); + SwitchFlowContext switchContext = + new SwitchFlowContext(flowContext, this, (breakLabel = new Label())); + + // analyse the block by considering specially the case/default statements (need to bind them + // to the entry point) + FlowInfo caseInits = FlowInfo.DeadEnd; + // in case of statements before the first case + preSwitchInitStateIndex = + currentScope.methodScope().recordInitializationStates(flowInfo); + int caseIndex = 0; + if (statements != null) { + for (int i = 0, max = statements.length; i < max; i++) { + Statement statement = statements[i]; + if ((caseIndex < caseCount) + && (statement == cases[caseIndex])) { // statements[i] is a case or a default case + caseIndex++; + caseInits = caseInits.mergedWith(flowInfo.copy().unconditionalInits()); + } else { + if (statement == defaultCase) { + caseInits = caseInits.mergedWith(flowInfo.copy().unconditionalInits()); + } + } + if (!caseInits.complainIfUnreachable(statement, scope)) { + caseInits = statement.analyseCode(scope, switchContext, caseInits); + } + } + } + + // if no default case, then record it may jump over the block directly to the end + if (defaultCase == null) { + // only retain the potential initializations + flowInfo.addPotentialInitializationsFrom( + caseInits.mergedWith(switchContext.initsOnBreak)); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(flowInfo); + return flowInfo; + } + + // merge all branches inits + FlowInfo mergedInfo = caseInits.mergedWith(switchContext.initsOnBreak); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + /** + * Switch code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + int[] sortedIndexes = new int[caseCount]; + int[] localKeysCopy; + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + + // prepare the labels and constants + breakLabel.codeStream = codeStream; + CaseLabel[] caseLabels = new CaseLabel[caseCount]; + int[] constants = new int[caseCount]; + boolean needSwitch = caseCount != 0; + for (int i = 0; i < caseCount; i++) { + constants[i] = cases[i].constantExpression.constant.intValue(); + cases[i].targetLabel = (caseLabels[i] = new CaseLabel(codeStream)); + } + + // we sort the keys to be able to generate the code for tableswitch or lookupswitch + for (int i = 0; i < caseCount; i++) { + sortedIndexes[i] = i; + } + System.arraycopy( + constants, + 0, + (localKeysCopy = new int[caseCount]), + 0, + caseCount); + CodeStream.sort(localKeysCopy, 0, caseCount - 1, sortedIndexes); + CaseLabel defaultLabel = new CaseLabel(codeStream); + if (defaultCase != null) { + defaultCase.targetLabel = defaultLabel; + } + // generate expression testes + testExpression.generateCode(currentScope, codeStream, needSwitch); + + // generate the appropriate switch table + if (needSwitch) { + int max = localKeysCopy[caseCount - 1]; + int min = localKeysCopy[0]; + if ((long) (caseCount * 2.5) > ((long) max - (long) min)) { + codeStream.tableswitch( + defaultLabel, + min, + max, + constants, + sortedIndexes, + caseLabels); + } else { + codeStream.lookupswitch(defaultLabel, constants, sortedIndexes, caseLabels); + } + codeStream.updateLastRecordedEndPC(codeStream.position); + } + // generate the switch block statements + int caseIndex = 0; + if (statements != null) { + for (int i = 0, maxCases = statements.length; i < maxCases; i++) { + Statement statement = statements[i]; + if ((caseIndex < caseCount) + && (statement == cases[caseIndex])) { // statements[i] is a case + if (preSwitchInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + preSwitchInitStateIndex); + caseIndex++; + } + } else { + if (statement == defaultCase) { // statements[i] is a case or a default case + if (preSwitchInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + preSwitchInitStateIndex); + } + } + } + statement.generateCode(scope, codeStream); + } + } + // place the trailing labels (for break and default case) + breakLabel.place(); + if (defaultCase == null) { + defaultLabel.place(); + } + // May loose some local variable initializations : affecting the local variable attributes + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + } + if (scope != currentScope) { + codeStream.exitUserScope(scope); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + + public void resetStateForCodeGeneration() { + + this.breakLabel.resetStateForCodeGeneration(); + } + + public void resolve(BlockScope upperScope) { + + TypeBinding testType = testExpression.resolveType(upperScope); + if (testType == null) + return; + testExpression.implicitWidening(testType, testType); + if (!(testExpression + .isConstantValueOfTypeAssignableToType(testType, IntBinding))) { + if (!upperScope.areTypesCompatible(testType, IntBinding)) { + upperScope.problemReporter().incorrectSwitchType(testExpression, testType); + return; + } + } + if (statements != null) { + scope = explicitDeclarations == 0 ? upperScope : new BlockScope(upperScope); + int length; + // collection of cases is too big but we will only iterate until caseCount + cases = new Case[length = statements.length]; + int[] casesValues = new int[length]; + int counter = 0; + for (int i = 0; i < length; i++) { + Constant cst; + if ((cst = statements[i].resolveCase(scope, testType, this)) != null) { + //----check for duplicate case statement------------ + if (cst != NotAConstant) { + int key = cst.intValue(); + for (int j = 0; j < counter; j++) { + if (casesValues[j] == key) { + scope.problemReporter().duplicateCase((Case) statements[i], cst); + } + } + casesValues[counter++] = key; + } + } + } + } + } + public String toString(int tab) { + + String inFront, s = tabString(tab); + inFront = s; + s = s + "switch (" + testExpression.toStringExpression() + ") "; //$NON-NLS-1$ //$NON-NLS-2$ + if (statements == null) { + s = s + "{}"; //$NON-NLS-1$ + return s; + } else + s = s + "{"; //$NON-NLS-1$ + s = s + + (explicitDeclarations != 0 + ? "// ---scope needed for " //$NON-NLS-1$ + + String.valueOf(explicitDeclarations) + + " locals------------ \n"//$NON-NLS-1$ + : "// ---NO scope needed------ \n"); //$NON-NLS-1$ + + int i = 0; + String tabulation = " "; //$NON-NLS-1$ + try { + while (true) { + //use instanceof in order not to polluate classes with behavior only needed for printing purpose. + if (statements[i] instanceof Expression) + s = s + "\n" + inFront + tabulation; //$NON-NLS-1$ + if (statements[i] instanceof Break) + s = s + statements[i].toString(0); + else + s = s + "\n" + statements[i].toString(tab + 2); //$NON-NLS-1$ + //============= + if ((statements[i] instanceof Case) + || (statements[i] instanceof DefaultCase)) { + i++; + while (!((statements[i] instanceof Case) + || (statements[i] instanceof DefaultCase))) { + if ((statements[i] instanceof Expression) || (statements[i] instanceof Break)) + s = s + statements[i].toString(0) + " ; "; //$NON-NLS-1$ + else + s = s + "\n" + statements[i].toString(tab + 6) + " ; "; //$NON-NLS-1$ //$NON-NLS-2$ + i++; + } + } else { + s = s + " ;"; //$NON-NLS-1$ + i++; + } + } + } catch (IndexOutOfBoundsException e) { + }; + s = s + "}"; //$NON-NLS-1$ + return s; + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + testExpression.traverse(visitor, scope); + if (statements != null) { + int statementsLength = statements.length; + for (int i = 0; i < statementsLength; i++) + statements[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, blockScope); + } + + /** + * Dispatch the call on its last statement. + */ + public void branchChainTo(Label label) { + + // in order to improve debug attributes for stepping (11431) + // we want to inline the jumps to #breakLabel which already got + // generated (if any), and have them directly branch to a better + // location (the argument label). + // we know at this point that the breakLabel already got placed + if (this.breakLabel.hasForwardReferences()) { + label.appendForwardReferencesFrom(this.breakLabel); + } + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/SynchronizedStatement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/SynchronizedStatement.java new file mode 100644 index 0000000..ee464a9 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/SynchronizedStatement.java @@ -0,0 +1,170 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class SynchronizedStatement extends Statement { + + public Expression expression; + public Block block; + public BlockScope scope; + + boolean blockExit; + public LocalVariableBinding synchroVariable; + static final char[] SecretLocalDeclarationName = " syncValue".toCharArray(); //$NON-NLS-1$ + + public SynchronizedStatement( + Expression expression, + Block statement, + int s, + int e) { + + this.expression = expression; + this.block = statement; + sourceEnd = e; + sourceStart = s; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // mark the synthetic variable as being used + synchroVariable.used = true; + + // simple propagation to subnodes + flowInfo = + block.analyseCode( + scope, + new InsideSubRoutineFlowContext(flowContext, this), + expression.analyseCode(scope, flowContext, flowInfo)); + + // optimizing code gen + if ((flowInfo == FlowInfo.DeadEnd) || flowInfo.isFakeReachable()) { + blockExit = true; + } + return flowInfo; + } + + /** + * Synchronized statement code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + + // generate the synchronization expression + expression.generateCode(scope, codeStream, true); + if (block.isEmptyBlock()) { + if ((synchroVariable.type == LongBinding) + || (synchroVariable.type == DoubleBinding)) { + codeStream.dup2(); + } else { + codeStream.dup(); + } + // only take the lock + codeStream.monitorenter(); + codeStream.monitorexit(); + } else { + // enter the monitor + codeStream.store(synchroVariable, true); + codeStream.monitorenter(); + + // generate the body of the synchronized block + ExceptionLabel anyExceptionHandler = new ExceptionLabel(codeStream, null); + //'null' denotes any kind of exception + block.generateCode(scope, codeStream); + Label endLabel = new Label(codeStream); + if (!blockExit) { + codeStream.load(synchroVariable); + codeStream.monitorexit(); + codeStream.goto_(endLabel); + } + // generate the body of the exception handler + anyExceptionHandler.placeEnd(); + anyExceptionHandler.place(); + codeStream.incrStackSize(1); + codeStream.load(synchroVariable); + codeStream.monitorexit(); + codeStream.athrow(); + if (!blockExit) { + endLabel.place(); + } + } + if (scope != currentScope) { + codeStream.exitUserScope(scope); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public void resolve(BlockScope upperScope) { + + // special scope for secret locals optimization. + scope = new BlockScope(upperScope); + TypeBinding type = expression.resolveType(scope); + if (type == null) + return; + switch (type.id) { + case (T_boolean) : + case (T_char) : + case (T_float) : + case (T_double) : + case (T_byte) : + case (T_short) : + case (T_int) : + case (T_long) : + scope.problemReporter().invalidTypeToSynchronize(expression, type); + break; + case (T_void) : + scope.problemReporter().illegalVoidExpression(expression); + break; + case (T_null) : + scope.problemReporter().invalidNullToSynchronize(expression); + break; + } + //continue even on errors in order to have the TC done into the statements + synchroVariable = new LocalVariableBinding(SecretLocalDeclarationName, type, AccDefault, false); + scope.addLocalVariable(synchroVariable); + synchroVariable.constant = NotAConstant; // not inlinable + expression.implicitWidening(type, type); + block.resolveUsing(scope); + } + + public String toString(int tab) { + + String s = tabString(tab); + s = s + "synchronized (" + expression.toStringExpression() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + s = s + "\n" + block.toString(tab + 1); //$NON-NLS-1$ + return s; + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + expression.traverse(visitor, scope); + block.traverse(visitor, scope); + } + visitor.endVisit(this, blockScope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ThisReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ThisReference.java new file mode 100644 index 0000000..9ae61ea --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ThisReference.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class ThisReference extends Reference { + + public static final ThisReference ThisImplicit = new ThisReference(); + +/** + * ThisReference constructor comment. + */ +public ThisReference() { + super(); +} +public ThisReference(int s, int sourceEnd) { + this(); + this.sourceStart = s ; + this.sourceEnd = sourceEnd; +} +protected boolean checkAccess(MethodScope methodScope) { + // this/super cannot be used in constructor call + if (methodScope.isConstructorCall) { + methodScope.problemReporter().fieldsOrThisBeforeConstructorInvocation(this); + return false; + } + + // static may not refer to this/super + if (methodScope.isStatic) { + methodScope.problemReporter().errorThisSuperInStatic(this); + return false; + } + return true; +} +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + int pc = codeStream.position; + if (valueRequired) + codeStream.aload_0(); + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public boolean isThis() { + + return true ; +} +public TypeBinding resolveType(BlockScope scope) { + // implicit this + constant = NotAConstant; + if (this != ThisImplicit && !checkAccess(scope.methodScope())) + return null; + return scope.enclosingSourceType(); +} +public String toStringExpression(){ + + if (this == ThisImplicit) return "" ; //$NON-NLS-1$ + return "this"; //$NON-NLS-1$ +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope blockScope) { + visitor.visit(this, blockScope); + visitor.endVisit(this, blockScope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ThrowStatement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ThrowStatement.java new file mode 100644 index 0000000..6aa082a --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ThrowStatement.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream; +import net.sourceforge.phpdt.internal.compiler.flow.FlowContext; +import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo; +import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; + +public class ThrowStatement extends Statement { + public Expression exception; + public TypeBinding exceptionType; + + public ThrowStatement(Expression exception, int startPosition) { + this.exception = exception; + this.sourceStart = startPosition; + this.sourceEnd = exception.sourceEnd; + } + + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + + exception.analyseCode(currentScope, flowContext, flowInfo); + // need to check that exception thrown is actually caught somewhere + flowContext.checkExceptionHandlers(exceptionType, this, flowInfo, currentScope); + return FlowInfo.DeadEnd; + } + + /** + * Throw code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) + return; + int pc = codeStream.position; + exception.generateCode(currentScope, codeStream, true); + codeStream.athrow(); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public void resolve(BlockScope scope) { + + exceptionType = exception.resolveTypeExpecting(scope, scope.getJavaLangThrowable()); + + if (exceptionType == NullBinding + && scope.environment().options.complianceLevel <= CompilerOptions.JDK1_3){ + // if compliant with 1.4, this problem will not be reported + scope.problemReporter().cannotThrowNull(this); + } + exception.implicitWidening(exceptionType, exceptionType); + } + + public String toString(int tab) { + String s = tabString(tab); + s = s + "throw "; //$NON-NLS-1$ + s = s + exception.toStringExpression(); + return s; + } + + public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope blockScope) { + if (visitor.visit(this, blockScope)) + exception.traverse(visitor, blockScope); + visitor.endVisit(this, blockScope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TrueLiteral.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TrueLiteral.java new file mode 100644 index 0000000..a3f05ae --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TrueLiteral.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream; +import net.sourceforge.phpdt.internal.compiler.codegen.Label; +import net.sourceforge.phpdt.internal.compiler.impl.Constant; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; + +public class TrueLiteral extends MagicLiteral { + static final char[] source = {'t' , 'r' , 'u' , 'e'}; +public TrueLiteral(int s , int e) { + super(s,e); +} +public void computeConstant() { + + constant = Constant.fromValue(true);} +/** + * Code generation for the true literal + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + int pc = codeStream.position; + if (valueRequired) + codeStream.iconst_1(); + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) { + + // trueLabel being not nil means that we will not fall through into the TRUE case + + int pc = codeStream.position; + // constant == true + if (valueRequired) { + if (falseLabel == null) { + // implicit falling through the FALSE case + if (trueLabel != null) { + codeStream.goto_(trueLabel); + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public TypeBinding literalType(BlockScope scope) { + return BooleanBinding; +} +/** + * + */ +public char[] source() { + return source; +} +public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TryStatement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TryStatement.java new file mode 100644 index 0000000..139dbbc --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TryStatement.java @@ -0,0 +1,525 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class TryStatement extends Statement { + + public Block tryBlock; + public Block[] catchBlocks; + public Argument[] catchArguments; + public Block finallyBlock; + BlockScope scope; + + public boolean subRoutineCannotReturn = true; + // should rename into subRoutineComplete to be set to false by default + + ReferenceBinding[] caughtExceptionTypes; + boolean tryBlockExit; + boolean[] catchExits; + public int[] preserveExceptionHandler; + + Label subRoutineStartLabel; + public LocalVariableBinding anyExceptionVariable, + returnAddressVariable, + secretReturnValue; + + public final static char[] SecretReturnName = " returnAddress".toCharArray(); //$NON-NLS-1$ + public final static char[] SecretAnyHandlerName = " anyExceptionHandler".toCharArray(); //$NON-NLS-1$ + public static final char[] SecretLocalDeclarationName = " returnValue".toCharArray(); //$NON-NLS-1$ + + // for local variables table attributes + int preTryInitStateIndex = -1; + int mergedInitStateIndex = -1; + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // Consider the try block and catch block so as to compute the intersection of initializations and + // the minimum exit relative depth amongst all of them. Then consider the subroutine, and append its + // initialization to the try/catch ones, if the subroutine completes normally. If the subroutine does not + // complete, then only keep this result for the rest of the analysis + + // process the finally block (subroutine) - create a context for the subroutine + + preTryInitStateIndex = + currentScope.methodScope().recordInitializationStates(flowInfo); + + if (anyExceptionVariable != null) { + anyExceptionVariable.used = true; + } + if (returnAddressVariable != null) { + returnAddressVariable.used = true; + } + InsideSubRoutineFlowContext insideSubContext; + FinallyFlowContext finallyContext; + UnconditionalFlowInfo subInfo; + if (subRoutineStartLabel == null) { + // no finally block + insideSubContext = null; + finallyContext = null; + subInfo = null; + } else { + // analyse finally block first + insideSubContext = new InsideSubRoutineFlowContext(flowContext, this); + subInfo = + finallyBlock + .analyseCode( + currentScope, + finallyContext = new FinallyFlowContext(flowContext, finallyBlock), + flowInfo.copy()) + .unconditionalInits(); + if (!((subInfo == FlowInfo.DeadEnd) || subInfo.isFakeReachable())) { + subRoutineCannotReturn = false; + } + } + // process the try block in a context handling the local exceptions. + ExceptionHandlingFlowContext handlingContext = + new ExceptionHandlingFlowContext( + insideSubContext == null ? flowContext : insideSubContext, + tryBlock, + caughtExceptionTypes, + scope, + flowInfo.unconditionalInits()); + + FlowInfo tryInfo; + if (tryBlock.statements == null) { + tryInfo = flowInfo; + tryBlockExit = false; + } else { + tryInfo = tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy()); + tryBlockExit = (tryInfo == FlowInfo.DeadEnd) || tryInfo.isFakeReachable(); + } + + // check unreachable catch blocks + handlingContext.complainIfUnusedExceptionHandlers(catchBlocks, scope, this); + + // process the catch blocks - computing the minimal exit depth amongst try/catch + if (catchArguments != null) { + int catchCount; + catchExits = new boolean[catchCount = catchBlocks.length]; + for (int i = 0; i < catchCount; i++) { + // keep track of the inits that could potentially have led to this exception handler (for final assignments diagnosis) + ///* + FlowInfo catchInfo = + flowInfo + .copy() + .unconditionalInits() + .addPotentialInitializationsFrom( + handlingContext.initsOnException(caughtExceptionTypes[i]).unconditionalInits()) + .addPotentialInitializationsFrom(tryInfo.unconditionalInits()) + .addPotentialInitializationsFrom(handlingContext.initsOnReturn); + + // catch var is always set + catchInfo.markAsDefinitelyAssigned(catchArguments[i].binding); + /* + "If we are about to consider an unchecked exception handler, potential inits may have occured inside + the try block that need to be detected , e.g. + try { x = 1; throwSomething();} catch(Exception e){ x = 2} " + "(uncheckedExceptionTypes notNil and: [uncheckedExceptionTypes at: index]) + ifTrue: [catchInits addPotentialInitializationsFrom: tryInits]." + */ + if (tryBlock.statements == null) { + catchInfo.markAsFakeReachable(true); + } + catchInfo = + catchBlocks[i].analyseCode( + currentScope, + insideSubContext == null ? flowContext : insideSubContext, + catchInfo); + catchExits[i] = + ((catchInfo == FlowInfo.DeadEnd) || catchInfo.isFakeReachable()); + tryInfo = tryInfo.mergedWith(catchInfo.unconditionalInits()); + } + } + if (subRoutineStartLabel == null) { + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(tryInfo); + return tryInfo; + } + + // we also need to check potential multiple assignments of final variables inside the finally block + // need to include potential inits from returns inside the try/catch parts - 1GK2AOF + tryInfo.addPotentialInitializationsFrom(insideSubContext.initsOnReturn); + finallyContext.complainOnRedundantFinalAssignments(tryInfo, currentScope); + if (subInfo == FlowInfo.DeadEnd) { + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(subInfo); + return subInfo; + } else { + FlowInfo mergedInfo = tryInfo.addInitializationsFrom(subInfo); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + } + + public boolean cannotReturn() { + + return subRoutineCannotReturn; + } + + /** + * Try statement code generation + * + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + if (tryBlock.isEmptyBlock()) { + if (subRoutineStartLabel != null) { + // since not passing the finallyScope, the block generation will exitUserScope(finallyScope) + finallyBlock.generateCode(scope, codeStream); + } + // May loose some local variable initializations : affecting the local variable attributes + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + } + // no local bytecode produced so no need for position remembering + return; + } + int pc = codeStream.position; + Label endLabel = new Label(codeStream); + boolean requiresNaturalJsr = false; + + // preparing exception labels + int maxCatches; + ExceptionLabel[] exceptionLabels = + new ExceptionLabel[maxCatches = + catchArguments == null ? 0 : catchArguments.length]; + for (int i = 0; i < maxCatches; i++) { + boolean preserveCurrentHandler = + (preserveExceptionHandler[i + / ExceptionHandlingFlowContext.BitCacheSize] + & (1 << (i % ExceptionHandlingFlowContext.BitCacheSize))) + != 0; + if (preserveCurrentHandler) { + exceptionLabels[i] = + new ExceptionLabel( + codeStream, + (ReferenceBinding) catchArguments[i].binding.type); + } + } + ExceptionLabel anyExceptionLabel = null; + if (subRoutineStartLabel != null) { + subRoutineStartLabel.codeStream = codeStream; + anyExceptionLabel = new ExceptionLabel(codeStream, null); + } + // generate the try block + tryBlock.generateCode(scope, codeStream); + boolean tryBlockHasSomeCode = codeStream.position != pc; + // flag telling if some bytecodes were issued inside the try block + + // natural exit: only if necessary + boolean nonReturningSubRoutine = + (subRoutineStartLabel != null) && subRoutineCannotReturn; + if ((!tryBlockExit) && tryBlockHasSomeCode) { + int position = codeStream.position; + if (nonReturningSubRoutine) { + codeStream.goto_(subRoutineStartLabel); + } else { + requiresNaturalJsr = true; + codeStream.goto_(endLabel); + } + codeStream.updateLastRecordedEndPC(position); + //goto is tagged as part of the try block + } + // place end positions of user-defined exception labels + if (tryBlockHasSomeCode) { + for (int i = 0; i < maxCatches; i++) { + boolean preserveCurrentHandler = + (preserveExceptionHandler[i + / ExceptionHandlingFlowContext.BitCacheSize] + & (1 << (i % ExceptionHandlingFlowContext.BitCacheSize))) + != 0; + if (preserveCurrentHandler) { + exceptionLabels[i].placeEnd(); + } + } + /* generate sequence of handler, all starting by storing the TOS (exception + thrown) into their own catch variables, the one specified in the source + that must denote the handled exception. + */ + if (catchArguments == null) { + if (anyExceptionLabel != null) { + anyExceptionLabel.placeEnd(); + } + } else { + for (int i = 0; i < maxCatches; i++) { + boolean preserveCurrentHandler = + (preserveExceptionHandler[i + / ExceptionHandlingFlowContext.BitCacheSize] + & (1 << (i % ExceptionHandlingFlowContext.BitCacheSize))) + != 0; + if (preserveCurrentHandler) { + // May loose some local variable initializations : affecting the local variable attributes + if (preTryInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + preTryInitStateIndex); + } + exceptionLabels[i].place(); + codeStream.incrStackSize(1); + // optimizing the case where the exception variable is not actually used + LocalVariableBinding catchVar; + int varPC = codeStream.position; + if ((catchVar = catchArguments[i].binding).resolvedPosition != -1) { + codeStream.store(catchVar, false); + catchVar.recordInitializationStartPC(codeStream.position); + codeStream.addVisibleLocalVariable(catchVar); + } else { + codeStream.pop(); + } + codeStream.recordPositionsFrom(varPC, catchArguments[i].sourceStart); + // Keep track of the pcs at diverging point for computing the local attribute + // since not passing the catchScope, the block generation will exitUserScope(catchScope) + catchBlocks[i].generateCode(scope, codeStream); + } + if (i == maxCatches - 1) { + if (anyExceptionLabel != null) { + anyExceptionLabel.placeEnd(); + } + if (subRoutineStartLabel != null) { + if (!catchExits[i] && preserveCurrentHandler) { + requiresNaturalJsr = true; + codeStream.goto_(endLabel); + } + } + } else { + if (!catchExits[i] && preserveCurrentHandler) { + if (nonReturningSubRoutine) { + codeStream.goto_(subRoutineStartLabel); + } else { + requiresNaturalJsr = true; + codeStream.goto_(endLabel); + } + } + } + } + } + // addition of a special handler so as to ensure that any uncaught exception (or exception thrown + // inside catch blocks) will run the finally block + int finallySequenceStartPC = codeStream.position; + if (subRoutineStartLabel != null) { + // the additional handler is doing: jsr finallyBlock and rethrow TOS-exception + anyExceptionLabel.place(); + + if (preTryInitStateIndex != -1) { + // reset initialization state, as for a normal catch block + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + preTryInitStateIndex); + } + + codeStream.incrStackSize(1); + if (nonReturningSubRoutine) { + codeStream.pop(); + // "if subroutine cannot return, no need to jsr/jump to subroutine since it will be entered in sequence + } else { + codeStream.store(anyExceptionVariable, false); + codeStream.jsr(subRoutineStartLabel); + codeStream.load(anyExceptionVariable); + codeStream.athrow(); + } + } + // end of catch sequence, place label that will correspond to the finally block beginning, or end of statement + endLabel.place(); + if (subRoutineStartLabel != null) { + if (nonReturningSubRoutine) { + requiresNaturalJsr = false; + } + Label veryEndLabel = new Label(codeStream); + if (requiresNaturalJsr) { + codeStream.jsr(subRoutineStartLabel); + codeStream.goto_(veryEndLabel); + } + subRoutineStartLabel.place(); + if (!nonReturningSubRoutine) { + codeStream.incrStackSize(1); + codeStream.store(returnAddressVariable, false); + } + codeStream.recordPositionsFrom( + finallySequenceStartPC, + finallyBlock.sourceStart); + // entire sequence for finally is associated to finally block + finallyBlock.generateCode(scope, codeStream); + if (!nonReturningSubRoutine) { + int position = codeStream.position; + codeStream.ret(returnAddressVariable.resolvedPosition); + codeStream.updateLastRecordedEndPC(position); + // the ret bytecode is part of the subroutine + } + if (requiresNaturalJsr) { + veryEndLabel.place(); + } + } + } else { + // try block had no effect, only generate the body of the finally block if any + if (subRoutineStartLabel != null) { + finallyBlock.generateCode(scope, codeStream); + } + } + // May loose some local variable initializations : affecting the local variable attributes + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public void resolve(BlockScope upperScope) { + + // special scope for secret locals optimization. + this.scope = new BlockScope(upperScope); + + BlockScope tryScope = new BlockScope(scope); + BlockScope finallyScope = null; + + if (finallyBlock != null + && finallyBlock.statements != null) { + + finallyScope = new BlockScope(scope, false); // don't add it yet to parent scope + + // provision for returning and forcing the finally block to run + MethodScope methodScope = scope.methodScope(); + + // the type does not matter as long as its not a normal base type + this.returnAddressVariable = + new LocalVariableBinding(SecretReturnName, upperScope.getJavaLangObject(), AccDefault, false); + finallyScope.addLocalVariable(returnAddressVariable); + this.returnAddressVariable.constant = NotAConstant; // not inlinable + this.subRoutineStartLabel = new Label(); + + this.anyExceptionVariable = + new LocalVariableBinding(SecretAnyHandlerName, scope.getJavaLangThrowable(), AccDefault, false); + finallyScope.addLocalVariable(this.anyExceptionVariable); + this.anyExceptionVariable.constant = NotAConstant; // not inlinable + + if (!methodScope.isInsideInitializer()) { + MethodBinding methodBinding = + ((AbstractMethodDeclaration) methodScope.referenceContext).binding; + if (methodBinding != null) { + TypeBinding methodReturnType = methodBinding.returnType; + if (methodReturnType.id != T_void) { + this.secretReturnValue = + new LocalVariableBinding( + SecretLocalDeclarationName, + methodReturnType, + AccDefault, + false); + finallyScope.addLocalVariable(this.secretReturnValue); + this.secretReturnValue.constant = NotAConstant; // not inlinable + } + } + } + finallyBlock.resolveUsing(finallyScope); + // force the finally scope to have variable positions shifted after its try scope and catch ones + finallyScope.shiftScopes = new BlockScope[catchArguments == null ? 1 : catchArguments.length+1]; + finallyScope.shiftScopes[0] = tryScope; + } + this.tryBlock.resolveUsing(tryScope); + + // arguments type are checked against JavaLangThrowable in resolveForCatch(..) + if (this.catchBlocks != null) { + int length = this.catchArguments.length; + TypeBinding[] argumentTypes = new TypeBinding[length]; + for (int i = 0; i < length; i++) { + BlockScope catchScope = new BlockScope(scope); + if (finallyScope != null){ + finallyScope.shiftScopes[i+1] = catchScope; + } + // side effect on catchScope in resolveForCatch(..) + if ((argumentTypes[i] = catchArguments[i].resolveForCatch(catchScope)) == null) + return; + catchBlocks[i].resolveUsing(catchScope); + } + + // Verify that the catch clause are ordered in the right way: + // more specialized first. + this.caughtExceptionTypes = new ReferenceBinding[length]; + for (int i = 0; i < length; i++) { + caughtExceptionTypes[i] = (ReferenceBinding) argumentTypes[i]; + for (int j = 0; j < i; j++) { + if (scope.areTypesCompatible(caughtExceptionTypes[i], argumentTypes[j])) { + scope.problemReporter().wrongSequenceOfExceptionTypesError(this, i, j); + return; + } + } + } + } else { + caughtExceptionTypes = new ReferenceBinding[0]; + } + + if (finallyScope != null){ + // add finallyScope as last subscope, so it can be shifted behind try/catch subscopes. + // the shifting is necessary to achieve no overlay in between the finally scope and its + // sibling in term of local variable positions. + this.scope.addSubscope(finallyScope); + } + } + + public String toString(int tab) { + String s = tabString(tab); + //try + s = s + "try "; //$NON-NLS-1$ + if (tryBlock == Block.None) + s = s + "{}"; //$NON-NLS-1$ + else + s = s + "\n" + tryBlock.toString(tab + 1); //$NON-NLS-1$ + + //catches + if (catchBlocks != null) + for (int i = 0; i < catchBlocks.length; i++) + s = s + "\n" + tabString(tab) + "catch (" //$NON-NLS-2$ //$NON-NLS-1$ + +catchArguments[i].toString(0) + ") " //$NON-NLS-1$ + +catchBlocks[i].toString(tab + 1); + //finally + if (finallyBlock != null) { + if (finallyBlock == Block.None) + s = s + "\n" + tabString(tab) + "finally {}"; //$NON-NLS-2$ //$NON-NLS-1$ + else + s = s + "\n" + tabString(tab) + "finally\n" + //$NON-NLS-2$ //$NON-NLS-1$ + finallyBlock.toString(tab + 1); + } + + return s; + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + tryBlock.traverse(visitor, scope); + if (catchArguments != null) { + for (int i = 0, max = catchBlocks.length; i < max; i++) { + catchArguments[i].traverse(visitor, scope); + catchBlocks[i].traverse(visitor, scope); + } + } + if (finallyBlock != null) + finallyBlock.traverse(visitor, scope); + } + visitor.endVisit(this, blockScope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TypeDeclaration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TypeDeclaration.java new file mode 100644 index 0000000..578857a --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TypeDeclaration.java @@ -0,0 +1,1069 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.*; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.parser.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; +import net.sourceforge.phpdt.internal.compiler.util.*; + +public class TypeDeclaration + extends Statement + implements ProblemSeverities, ReferenceContext { + + public int modifiers; + public int modifiersSourceStart; + public char[] name; + public TypeReference superclass; + public TypeReference[] superInterfaces; + public FieldDeclaration[] fields; + public AbstractMethodDeclaration[] methods; + public MemberTypeDeclaration[] memberTypes; + public SourceTypeBinding binding; + public ClassScope scope; + public MethodScope initializerScope; + public MethodScope staticInitializerScope; + public boolean ignoreFurtherInvestigation = false; + public int maxFieldCount; + public int declarationSourceStart; + public int declarationSourceEnd; + public int bodyStart; + public int bodyEnd; // doesn't include the trailing comment if any. + protected boolean hasBeenGenerated = false; + public CompilationResult compilationResult; + private MethodDeclaration[] missingAbstractMethods; + + public TypeDeclaration(CompilationResult compilationResult){ + this.compilationResult = compilationResult; + } + + /* + * We cause the compilation task to abort to a given extent. + */ + public void abort(int abortLevel) { + + if (scope == null) { + throw new AbortCompilation(); // cannot do better + } + + CompilationResult compilationResult = + scope.referenceCompilationUnit().compilationResult; + + switch (abortLevel) { + case AbortCompilation : + throw new AbortCompilation(compilationResult); + case AbortCompilationUnit : + throw new AbortCompilationUnit(compilationResult); + case AbortMethod : + throw new AbortMethod(compilationResult); + default : + throw new AbortType(compilationResult); + } + } + /** + * This method is responsible for adding a method declaration to the type method collections. + * Note that this implementation is inserting it in first place (as VAJ or javac), and that this + * impacts the behavior of the method ConstantPool.resetForClinit(int. int), in so far as + * the latter will have to reset the constant pool state accordingly (if it was added first, it does + * not need to preserve some of the method specific cached entries since this will be the first method). + * inserts the clinit method declaration in the first position. + * + * @see org.eclipse.jdt.internal.compiler.codegen.ConstantPool#resetForClinit(int, int) + */ + public final void addClinit() { + + //see comment on needClassInitMethod + if (needClassInitMethod()) { + int length; + AbstractMethodDeclaration[] methods; + if ((methods = this.methods) == null) { + length = 0; + methods = new AbstractMethodDeclaration[1]; + } else { + length = methods.length; + System.arraycopy( + methods, + 0, + (methods = new AbstractMethodDeclaration[length + 1]), + 1, + length); + } + Clinit clinit = new Clinit(this.compilationResult); + methods[0] = clinit; + // clinit is added in first location, so as to minimize the use of ldcw (big consumer of constant inits) + clinit.declarationSourceStart = clinit.sourceStart = sourceStart; + clinit.declarationSourceEnd = clinit.sourceEnd = sourceEnd; + clinit.bodyEnd = sourceEnd; + this.methods = methods; + } + } + + /** + * Flow analysis for a local innertype + * + */ + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + if (ignoreFurtherInvestigation) + return flowInfo; + try { + // remember local types binding for innerclass emulation propagation + currentScope.referenceCompilationUnit().record((LocalTypeBinding) binding); + + InitializationFlowContext initializerContext = + new InitializationFlowContext(null, this, initializerScope); + // propagate down the max field count + updateMaxFieldCount(); + FlowInfo fieldInfo = flowInfo.copy(); + // so as not to propagate changes outside this type + if (fields != null) { + for (int i = 0, count = fields.length; i < count; i++) { + fieldInfo = + fields[i].analyseCode(initializerScope, initializerContext, fieldInfo); + if (fieldInfo == FlowInfo.DeadEnd) { + // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable + // branch, since the previous initializer already got the blame. + initializerScope.problemReporter().initializerMustCompleteNormally(fields[i]); + fieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true); + } + } + } + if (memberTypes != null) { + for (int i = 0, count = memberTypes.length; i < count; i++) { + memberTypes[i].analyseCode(scope, flowContext, fieldInfo.copy()); + } + } + if (methods != null) { + int recursionBalance = 0; // check constructor recursions + for (int i = 0, count = methods.length; i < count; i++) { + AbstractMethodDeclaration method = methods[i]; + if (method.ignoreFurtherInvestigation) + continue; + if (method.isConstructor()) { // constructor + ConstructorDeclaration constructor = (ConstructorDeclaration) method; + constructor.analyseCode(scope, initializerContext, fieldInfo.copy()); + // compute the recursive invocation balance: + // how many thisReferences vs. superReferences to constructors + int refCount; + if ((refCount = constructor.referenceCount) > 0) { + if ((constructor.constructorCall == null) + || constructor.constructorCall.isSuperAccess() + || !constructor.constructorCall.binding.isValidBinding()) { + recursionBalance -= refCount; + constructor.referenceCount = -1; + // for error reporting propagation + } else { + recursionBalance += refCount; + } + } + } else { // regular method + method.analyseCode(scope, null, flowInfo.copy()); + } + } + if (recursionBalance > 0) { + // there is one or more cycle(s) amongst constructor invocations + scope.problemReporter().recursiveConstructorInvocation(this); + } + } + } catch (AbortType e) { + this.ignoreFurtherInvestigation = true; + } + return flowInfo; + } + + /** + * Flow analysis for a member innertype + * + */ + public void analyseCode(ClassScope classScope1) { + + if (ignoreFurtherInvestigation) + return; + try { + // propagate down the max field count + updateMaxFieldCount(); + FlowInfo flowInfo = FlowInfo.initial(maxFieldCount); // start fresh init info + InitializationFlowContext initializerContext = + new InitializationFlowContext(null, this, initializerScope); + InitializationFlowContext staticInitializerContext = + new InitializationFlowContext(null, this, staticInitializerScope); + FlowInfo nonStaticFieldInfo = flowInfo.copy(), + staticFieldInfo = flowInfo.copy(); + if (fields != null) { + for (int i = 0, count = fields.length; i < count; i++) { + if (fields[i].isStatic()) { + staticFieldInfo = + fields[i].analyseCode( + staticInitializerScope, + staticInitializerContext, + staticFieldInfo); + // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable + // branch, since the previous initializer already got the blame. + if (staticFieldInfo == FlowInfo.DeadEnd) { + staticInitializerScope.problemReporter().initializerMustCompleteNormally( + fields[i]); + staticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true); + } + } else { + nonStaticFieldInfo = + fields[i].analyseCode(initializerScope, initializerContext, nonStaticFieldInfo); + // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable + // branch, since the previous initializer already got the blame. + if (nonStaticFieldInfo == FlowInfo.DeadEnd) { + initializerScope.problemReporter().initializerMustCompleteNormally(fields[i]); + nonStaticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true); + } + } + } + } + if (memberTypes != null) { + for (int i = 0, count = memberTypes.length; i < count; i++) { + memberTypes[i].analyseCode(scope); + } + } + if (methods != null) { + int recursionBalance = 0; // check constructor recursions + for (int i = 0, count = methods.length; i < count; i++) { + AbstractMethodDeclaration method = methods[i]; + if (method.ignoreFurtherInvestigation) + continue; + if (method.isInitializationMethod()) { + if (method.isStatic()) { // + ((Clinit) method).analyseCode(scope, staticInitializerContext, staticFieldInfo); + } else { // constructor + ConstructorDeclaration constructor = (ConstructorDeclaration) method; + constructor.analyseCode(scope, initializerContext, nonStaticFieldInfo.copy()); + // compute the recursive invocation balance: + // how many thisReferences vs. superReferences to constructors + int refCount; + if ((refCount = constructor.referenceCount) > 0) { + if ((constructor.constructorCall == null) + || constructor.constructorCall.isSuperAccess() + || !constructor.constructorCall.binding.isValidBinding()) { + recursionBalance -= refCount; + constructor.referenceCount = -1; // for error reporting propagation + } else { + recursionBalance += refCount; + } + } + } + } else { // regular method + method.analyseCode(scope, null, FlowInfo.initial(maxFieldCount)); + } + } + if (recursionBalance > 0) { + // there is one or more cycle(s) amongst constructor invocations + scope.problemReporter().recursiveConstructorInvocation(this); + } + } + } catch (AbortType e) { + this.ignoreFurtherInvestigation = true; + }; + } + + /** + * Flow analysis for a local member innertype + * + */ + public void analyseCode( + ClassScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + if (ignoreFurtherInvestigation) + return; + try { + // remember local types binding for innerclass emulation propagation + currentScope.referenceCompilationUnit().record((LocalTypeBinding) binding); + + /* force to emulation of access to direct enclosing instance: only for local members. + * By using the initializer scope, we actually only request an argument emulation, the + * field is not added until actually used. However we will force allocations to be qualified + * with an enclosing instance. + */ + initializerScope.emulateOuterAccess( + (SourceTypeBinding) binding.enclosingType(), + false); + + InitializationFlowContext initializerContext = + new InitializationFlowContext(null, this, initializerScope); + // propagate down the max field count + updateMaxFieldCount(); + FlowInfo fieldInfo = flowInfo.copy(); + // so as not to propagate changes outside this type + if (fields != null) { + for (int i = 0, count = fields.length; i < count; i++) { + if (!fields[i].isStatic()) { + fieldInfo = + fields[i].analyseCode(initializerScope, initializerContext, fieldInfo); + if (fieldInfo == FlowInfo.DeadEnd) { + // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable + // branch, since the previous initializer already got the blame. + initializerScope.problemReporter().initializerMustCompleteNormally(fields[i]); + fieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true); + } + } + } + } + if (memberTypes != null) { + for (int i = 0, count = memberTypes.length; i < count; i++) { + memberTypes[i].analyseCode(scope, flowContext, fieldInfo.copy()); + } + } + if (methods != null) { + int recursionBalance = 0; // check constructor recursions + for (int i = 0, count = methods.length; i < count; i++) { + AbstractMethodDeclaration method = methods[i]; + if (method.ignoreFurtherInvestigation) + continue; + if (method.isConstructor()) { // constructor + ConstructorDeclaration constructor = (ConstructorDeclaration) method; + constructor.analyseCode(scope, initializerContext, fieldInfo.copy()); + // compute the recursive invocation balance: + // how many thisReferences vs. superReferences to constructors + int refCount; + if ((refCount = constructor.referenceCount) > 0) { + if ((constructor.constructorCall == null) + || constructor.constructorCall.isSuperAccess() + || !constructor.constructorCall.binding.isValidBinding()) { + recursionBalance -= refCount; + constructor.referenceCount = -1; // for error reporting propagation + } else { + recursionBalance += refCount; + } + } + } else { // regular method + method.analyseCode(scope, null, flowInfo.copy()); + } + } + if (recursionBalance > 0) { + // there is one or more cycle(s) amongst constructor invocations + scope.problemReporter().recursiveConstructorInvocation(this); + } + } + } catch (AbortType e) { + this.ignoreFurtherInvestigation = true; + }; + } + + /** + * Flow analysis for a package member type + * + */ + public void analyseCode(CompilationUnitScope unitScope) { + + if (ignoreFurtherInvestigation) + return; + try { + FlowInfo flowInfo = FlowInfo.initial(maxFieldCount); // start fresh init info + InitializationFlowContext initializerContext = + new InitializationFlowContext(null, this, initializerScope); + InitializationFlowContext staticInitializerContext = + new InitializationFlowContext(null, this, staticInitializerScope); + FlowInfo nonStaticFieldInfo = flowInfo.copy(), + staticFieldInfo = flowInfo.copy(); + if (fields != null) { + for (int i = 0, count = fields.length; i < count; i++) { + if (fields[i].isStatic()) { + staticFieldInfo = + fields[i].analyseCode( + staticInitializerScope, + staticInitializerContext, + staticFieldInfo); + // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable + // branch, since the previous initializer already got the blame. + if (staticFieldInfo == FlowInfo.DeadEnd) { + staticInitializerScope.problemReporter().initializerMustCompleteNormally( + fields[i]); + staticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true); + } + } else { + nonStaticFieldInfo = + fields[i].analyseCode(initializerScope, initializerContext, nonStaticFieldInfo); + // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable + // branch, since the previous initializer already got the blame. + if (nonStaticFieldInfo == FlowInfo.DeadEnd) { + initializerScope.problemReporter().initializerMustCompleteNormally(fields[i]); + nonStaticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true); + } + } + } + } + if (memberTypes != null) { + for (int i = 0, count = memberTypes.length; i < count; i++) { + memberTypes[i].analyseCode(scope); + } + } + if (methods != null) { + int recursionBalance = 0; // check constructor recursions + for (int i = 0, count = methods.length; i < count; i++) { + AbstractMethodDeclaration method = methods[i]; + if (method.ignoreFurtherInvestigation) + continue; + if (method.isInitializationMethod()) { + if (method.isStatic()) { // + ((Clinit) method).analyseCode(scope, staticInitializerContext, staticFieldInfo); + } else { // constructor + ConstructorDeclaration constructor = (ConstructorDeclaration) method; + constructor.analyseCode(scope, initializerContext, nonStaticFieldInfo.copy()); + // compute the recursive invocation balance: + // how many thisReferences vs. superReferences to constructors + int refCount; + if ((refCount = constructor.referenceCount) > 0) { + if ((constructor.constructorCall == null) + || constructor.constructorCall.isSuperAccess() + || !constructor.constructorCall.binding.isValidBinding()) { + recursionBalance -= refCount; + constructor.referenceCount = -1; // for error reporting propagation + } else { + recursionBalance += refCount; + } + } + } + } else { // regular method + method.analyseCode(scope, null, FlowInfo.initial(maxFieldCount)); + } + } + if (recursionBalance > 0) { + // there is one or more cycle(s) amongst constructor invocations + scope.problemReporter().recursiveConstructorInvocation(this); + } + } + } catch (AbortType e) { + this.ignoreFurtherInvestigation = true; + }; + } + + /* + * Check for constructor vs. method with no return type. + * Answers true if at least one constructor is defined + */ + public boolean checkConstructors(Parser parser) { + + //if a constructor has not the name of the type, + //convert it into a method with 'null' as its return type + boolean hasConstructor = false; + if (methods != null) { + for (int i = methods.length; --i >= 0;) { + AbstractMethodDeclaration am; + if ((am = methods[i]).isConstructor()) { + if (!CharOperation.equals(am.selector, name)) { + // the constructor was in fact a method with no return type + // unless an explicit constructor call was supplied + ConstructorDeclaration c = (ConstructorDeclaration) am; + if ((c.constructorCall == null) + || (c.constructorCall.isImplicitSuper())) { //changed to a method + MethodDeclaration m = new MethodDeclaration(this.compilationResult); + m.sourceStart = c.sourceStart; + m.sourceEnd = c.sourceEnd; + m.bodyStart = c.bodyStart; + m.bodyEnd = c.bodyEnd; + m.declarationSourceEnd = c.declarationSourceEnd; + m.declarationSourceStart = c.declarationSourceStart; + m.selector = c.selector; + m.statements = c.statements; + m.modifiers = c.modifiers; + m.arguments = c.arguments; + m.thrownExceptions = c.thrownExceptions; + m.explicitDeclarations = c.explicitDeclarations; + m.returnType = null; + methods[i] = m; + } + } else { + if (this.isInterface()) { + // report the problem and continue the parsing + parser.problemReporter().interfaceCannotHaveConstructors( + (ConstructorDeclaration) am); + } + hasConstructor = true; + } + } + } + } + return hasConstructor; + } + + public CompilationResult compilationResult() { + + return this.compilationResult; + } + + public ConstructorDeclaration createsInternalConstructor( + boolean needExplicitConstructorCall, + boolean needToInsert) { + + //Add to method'set, the default constuctor that just recall the + //super constructor with no arguments + //The arguments' type will be positionned by the TC so just use + //the default int instead of just null (consistency purpose) + + //the constructor + ConstructorDeclaration constructor = new ConstructorDeclaration(this.compilationResult); + constructor.isDefaultConstructor = true; + constructor.selector = name; + if (modifiers != AccDefault) { + constructor.modifiers = + ((this instanceof MemberTypeDeclaration) && (modifiers & AccPrivate) != 0) + ? AccDefault + : modifiers & AccVisibilityMASK; + } + + //if you change this setting, please update the + //SourceIndexer2.buildTypeDeclaration(TypeDeclaration,char[]) method + constructor.declarationSourceStart = constructor.sourceStart = sourceStart; + constructor.declarationSourceEnd = + constructor.sourceEnd = constructor.bodyEnd = sourceEnd; + + //the super call inside the constructor + if (needExplicitConstructorCall) { + constructor.constructorCall = + new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); + constructor.constructorCall.sourceStart = sourceStart; + constructor.constructorCall.sourceEnd = sourceEnd; + } + + //adding the constructor in the methods list + if (needToInsert) { + if (methods == null) { + methods = new AbstractMethodDeclaration[] { constructor }; + } else { + AbstractMethodDeclaration[] newMethods; + System.arraycopy( + methods, + 0, + newMethods = new AbstractMethodDeclaration[methods.length + 1], + 1, + methods.length); + newMethods[0] = constructor; + methods = newMethods; + } + } + return constructor; + } + + /** + * INTERNAL USE ONLY - Creates a fake method declaration for the corresponding binding. + * It is used to report errors for missing abstract methods. + */ + public MethodDeclaration addMissingAbstractMethodFor(MethodBinding methodBinding) { + TypeBinding[] argumentTypes = methodBinding.parameters; + int argumentsLength = argumentTypes.length; + //the constructor + MethodDeclaration methodDeclaration = new MethodDeclaration(this.compilationResult); + methodDeclaration.selector = methodBinding.selector; + methodDeclaration.sourceStart = sourceStart; + methodDeclaration.sourceEnd = sourceEnd; + methodDeclaration.modifiers = methodBinding.getAccessFlags() & ~AccAbstract; + + if (argumentsLength > 0) { + String baseName = "arg";//$NON-NLS-1$ + Argument[] arguments = (methodDeclaration.arguments = new Argument[argumentsLength]); + for (int i = argumentsLength; --i >= 0;) { + arguments[i] = new Argument((baseName + i).toCharArray(), 0L, null /*type ref*/, AccDefault); + } + } + + //adding the constructor in the methods list + if (this.missingAbstractMethods == null) { + this.missingAbstractMethods = new MethodDeclaration[] { methodDeclaration }; + } else { + MethodDeclaration[] newMethods; + System.arraycopy( + this.missingAbstractMethods, + 0, + newMethods = new MethodDeclaration[this.missingAbstractMethods.length + 1], + 1, + this.missingAbstractMethods.length); + newMethods[0] = methodDeclaration; + this.missingAbstractMethods = newMethods; + } + + //============BINDING UPDATE========================== + methodDeclaration.binding = new MethodBinding( + methodDeclaration.modifiers, //methodDeclaration + methodBinding.selector, + methodBinding.returnType, + argumentsLength == 0 ? NoParameters : argumentTypes, //arguments bindings + methodBinding.thrownExceptions, //exceptions + binding); //declaringClass + + methodDeclaration.scope = new MethodScope(scope, methodDeclaration, true); + methodDeclaration.bindArguments(); + +/* if (binding.methods == null) { + binding.methods = new MethodBinding[] { methodDeclaration.binding }; + } else { + MethodBinding[] newMethods; + System.arraycopy( + binding.methods, + 0, + newMethods = new MethodBinding[binding.methods.length + 1], + 1, + binding.methods.length); + newMethods[0] = methodDeclaration.binding; + binding.methods = newMethods; + }*/ + //=================================================== + + return methodDeclaration; + } + + /* + * Find the matching parse node, answers null if nothing found + */ + public FieldDeclaration declarationOf(FieldBinding fieldBinding) { + + if (fieldBinding != null) { + for (int i = 0, max = this.fields.length; i < max; i++) { + FieldDeclaration fieldDecl; + if ((fieldDecl = this.fields[i]).binding == fieldBinding) + return fieldDecl; + } + } + return null; + } + + /* + * Find the matching parse node, answers null if nothing found + */ + public TypeDeclaration declarationOf(MemberTypeBinding memberTypeBinding) { + + if (memberTypeBinding != null) { + for (int i = 0, max = this.memberTypes.length; i < max; i++) { + TypeDeclaration memberTypeDecl; + if ((memberTypeDecl = this.memberTypes[i]).binding == memberTypeBinding) + return memberTypeDecl; + } + } + return null; + } + + /* + * Find the matching parse node, answers null if nothing found + */ + public AbstractMethodDeclaration declarationOf(MethodBinding methodBinding) { + + if (methodBinding != null) { + for (int i = 0, max = this.methods.length; i < max; i++) { + AbstractMethodDeclaration methodDecl; + + if ((methodDecl = this.methods[i]).binding == methodBinding) + return methodDecl; + } + } + return null; + } + + /* + * Finds the matching type amoung this type's member types. + * Returns null if no type with this name is found. + * The type name is a compound name relative to this type + * eg. if this type is X and we're looking for Y.X.A.B + * then a type name would be {X, A, B} + */ + public TypeDeclaration declarationOfType(char[][] typeName) { + + int typeNameLength = typeName.length; + if (typeNameLength < 1 || !CharOperation.equals(typeName[0], this.name)) { + return null; + } + if (typeNameLength == 1) { + return this; + } + char[][] subTypeName = new char[typeNameLength - 1][]; + System.arraycopy(typeName, 1, subTypeName, 0, typeNameLength - 1); + for (int i = 0; i < this.memberTypes.length; i++) { + TypeDeclaration typeDecl = this.memberTypes[i].declarationOfType(subTypeName); + if (typeDecl != null) { + return typeDecl; + } + } + return null; + } + + /** + * Generic bytecode generation for type + */ + public void generateCode(ClassFile enclosingClassFile) { + + if (hasBeenGenerated) + return; + hasBeenGenerated = true; + if (ignoreFurtherInvestigation) { + if (binding == null) + return; + ClassFile.createProblemType( + this, + scope.referenceCompilationUnit().compilationResult); + return; + } + try { + // create the result for a compiled type + ClassFile classFile = new ClassFile(binding, enclosingClassFile, false); + // generate all fiels + classFile.addFieldInfos(); + + // record the inner type inside its own .class file to be able + // to generate inner classes attributes + if (binding.isMemberType()) + classFile.recordEnclosingTypeAttributes(binding); + if (binding.isLocalType()) { + enclosingClassFile.recordNestedLocalAttribute(binding); + classFile.recordNestedLocalAttribute(binding); + } + if (memberTypes != null) { + for (int i = 0, max = memberTypes.length; i < max; i++) { + // record the inner type inside its own .class file to be able + // to generate inner classes attributes + classFile.recordNestedMemberAttribute(memberTypes[i].binding); + memberTypes[i].generateCode(scope, classFile); + } + } + // generate all methods + classFile.setForMethodInfos(); + if (methods != null) { + for (int i = 0, max = methods.length; i < max; i++) { + methods[i].generateCode(scope, classFile); + } + } + + classFile.generateMissingAbstractMethods(this.missingAbstractMethods, scope.referenceCompilationUnit().compilationResult); + + // generate all methods + classFile.addSpecialMethods(); + + if (ignoreFurtherInvestigation) { // trigger problem type generation for code gen errors + throw new AbortType(scope.referenceCompilationUnit().compilationResult); + } + + // finalize the compiled type result + classFile.addAttributes(); + scope.referenceCompilationUnit().compilationResult.record( + binding.constantPoolName(), + classFile); + } catch (AbortType e) { + if (binding == null) + return; + ClassFile.createProblemType( + this, + scope.referenceCompilationUnit().compilationResult); + } + } + + /** + * Bytecode generation for a local inner type (API as a normal statement code gen) + */ + public void generateCode(BlockScope blockScope, CodeStream codeStream) { + + if (hasBeenGenerated) + return; + int pc = codeStream.position; + if (binding != null) { + ((NestedTypeBinding) binding).computeSyntheticArgumentsOffset(); + } + generateCode(codeStream.classFile); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + /** + * Bytecode generation for a member inner type + */ + public void generateCode(ClassScope classScope, ClassFile enclosingClassFile) { + + if (hasBeenGenerated) + return; + ((NestedTypeBinding) binding).computeSyntheticArgumentsOffset(); + generateCode(enclosingClassFile); + } + + /** + * Bytecode generation for a package member + */ + public void generateCode(CompilationUnitScope unitScope) { + + generateCode((ClassFile) null); + } + + public boolean isInterface() { + + return (modifiers & AccInterface) != 0; + } + + public boolean hasErrors() { + return this.ignoreFurtherInvestigation; + } + + /** + * A will be requested as soon as static fields or assertions are present. It will be eliminated during + * classfile creation if no bytecode was actually produced based on some optimizations/compiler settings. + */ + public final boolean needClassInitMethod() { + + // always need a when assertions are present + if ((this.bits & AddAssertionMASK) != 0) + return true; + if (fields == null) + return false; + if (isInterface()) + return true; // fields are implicitly statics + for (int i = fields.length; --i >= 0;) { + FieldDeclaration field = fields[i]; + //need to test the modifier directly while there is no binding yet + if ((field.modifiers & AccStatic) != 0) + return true; + } + return false; + } + + public void parseMethod(Parser parser, CompilationUnitDeclaration unit) { + + //connect method bodies + if (unit.ignoreMethodBodies) + return; + + // no scope were created, so cannot report further errors +// if (binding == null) +// return; + + //members + if (memberTypes != null) { + for (int i = memberTypes.length; --i >= 0;) + memberTypes[i].parseMethod(parser, unit); + } + + //methods + if (methods != null) { + for (int i = methods.length; --i >= 0;) + methods[i].parseStatements(parser, unit); + } + + //initializers + if (fields != null) { + for (int i = fields.length; --i >= 0;) { + if (fields[i] instanceof Initializer) { + ((Initializer) fields[i]).parseStatements(parser, this, unit); + } + } + } + } + + public void resolve() { + + if (binding == null) { + ignoreFurtherInvestigation = true; + return; + } + + try { + // check superclass & interfaces + if (binding.superclass != null) // watch out for Object ! (and other roots) + if (isTypeUseDeprecated(binding.superclass, scope)) + scope.problemReporter().deprecatedType(binding.superclass, superclass); + if (superInterfaces != null) + for (int i = superInterfaces.length; --i >= 0;) + if (superInterfaces[i].binding != null) + if (isTypeUseDeprecated(superInterfaces[i].binding, scope)) + scope.problemReporter().deprecatedType( + superInterfaces[i].binding, + superInterfaces[i]); + maxFieldCount = 0; + int lastFieldID = -1; + if (fields != null) { + for (int i = 0, count = fields.length; i < count; i++) { + FieldDeclaration field = fields[i]; + if (field.isField()) { + if (field.binding == null) { + ignoreFurtherInvestigation = true; + continue; + } + maxFieldCount++; + lastFieldID = field.binding.id; + } else { // initializer + ((Initializer) field).lastFieldID = lastFieldID + 1; + } + field.resolve(field.isStatic() ? staticInitializerScope : initializerScope); + } + } + if (memberTypes != null) + for (int i = 0, count = memberTypes.length; i < count; i++) + memberTypes[i].resolve(scope); + if (methods != null) + for (int i = 0, count = methods.length; i < count; i++) + methods[i].resolve(scope); + } catch (AbortType e) { + this.ignoreFurtherInvestigation = true; + return; + }; + } + + public void resolve(BlockScope blockScope) { + // local type declaration + + // need to build its scope first and proceed with binding's creation + blockScope.addLocalType(this); + + // and TC.... + if (binding != null) { + // binding is not set if the receiver could not be created + resolve(); + updateMaxFieldCount(); + } + } + + public void resolve(ClassScope upperScope) { + // member scopes are already created + // request the construction of a binding if local member type + + resolve(); + updateMaxFieldCount(); + } + + public void resolve(CompilationUnitScope upperScope) { + // top level : scope are already created + + resolve(); + updateMaxFieldCount(); + } + + public void tagAsHavingErrors() { + ignoreFurtherInvestigation = true; + } + + public String toString(int tab) { + + return tabString(tab) + toStringHeader() + toStringBody(tab); + } + + public String toStringBody(int tab) { + + String s = " {"; //$NON-NLS-1$ + if (memberTypes != null) { + for (int i = 0; i < memberTypes.length; i++) { + if (memberTypes[i] != null) { + s += "\n" + memberTypes[i].toString(tab + 1); //$NON-NLS-1$ + } + } + } + if (fields != null) { + for (int fieldI = 0; fieldI < fields.length; fieldI++) { + if (fields[fieldI] != null) { + s += "\n" + fields[fieldI].toString(tab + 1); //$NON-NLS-1$ + if (fields[fieldI].isField()) + s += ";"; //$NON-NLS-1$ + } + } + } + if (methods != null) { + for (int i = 0; i < methods.length; i++) { + if (methods[i] != null) { + s += "\n" + methods[i].toString(tab + 1); //$NON-NLS-1$ + } + } + } + s += "\n" + tabString(tab) + "}"; //$NON-NLS-2$ //$NON-NLS-1$ + return s; + } + + public String toStringHeader() { + + String s = ""; //$NON-NLS-1$ + if (modifiers != AccDefault) { + s += modifiersString(modifiers); + } + s += (isInterface() ? "interface " : "class ") + new String(name);//$NON-NLS-1$ //$NON-NLS-2$ + if (superclass != null) + s += " extends " + superclass.toString(0); //$NON-NLS-1$ + if (superInterfaces != null && superInterfaces.length > 0) { + s += (isInterface() ? " extends " : " implements ");//$NON-NLS-2$ //$NON-NLS-1$ + for (int i = 0; i < superInterfaces.length; i++) { + s += superInterfaces[i].toString(0); + if (i != superInterfaces.length - 1) + s += ", "; //$NON-NLS-1$ + }; + }; + return s; + } + + /** + * Iteration for a package member type + * + */ + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + CompilationUnitScope unitScope) { + + if (ignoreFurtherInvestigation) + return; + try { + if (visitor.visit(this, unitScope)) { + if (superclass != null) + superclass.traverse(visitor, scope); + if (superInterfaces != null) { + int superInterfaceLength = superInterfaces.length; + for (int i = 0; i < superInterfaceLength; i++) + superInterfaces[i].traverse(visitor, scope); + } + if (memberTypes != null) { + int memberTypesLength = memberTypes.length; + for (int i = 0; i < memberTypesLength; i++) + memberTypes[i].traverse(visitor, scope); + } + if (fields != null) { + int fieldsLength = fields.length; + for (int i = 0; i < fieldsLength; i++) { + FieldDeclaration field; + if ((field = fields[i]).isStatic()) { + field.traverse(visitor, staticInitializerScope); + } else { + field.traverse(visitor, initializerScope); + } + } + } + if (methods != null) { + int methodsLength = methods.length; + for (int i = 0; i < methodsLength; i++) + methods[i].traverse(visitor, scope); + } + } + } catch (AbortType e) { + } + } + + /** + * MaxFieldCount's computation is necessary so as to reserve space for + * the flow info field portions. It corresponds to the maximum amount of + * fields this class or one of its innertypes have. + * + * During name resolution, types are traversed, and the max field count is recorded + * on the outermost type. It is then propagated down during the flow analysis. + * + * This method is doing either up/down propagation. + */ + void updateMaxFieldCount() { + + if (binding == null) + return; // error scenario + TypeDeclaration outerMostType = scope.outerMostClassScope().referenceType(); + if (maxFieldCount > outerMostType.maxFieldCount) { + outerMostType.maxFieldCount = maxFieldCount; // up + } else { + maxFieldCount = outerMostType.maxFieldCount; // down + } + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TypeReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TypeReference.java new file mode 100644 index 0000000..d8c957f --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TypeReference.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public abstract class TypeReference extends Expression { + public TypeBinding binding; +public TypeReference() { + super () ; + } +// allows us to trap completion & selection nodes + +public void aboutToResolve(Scope scope) {} +/* + * Answer a base type reference (can be an array of base type). + */ +public static final TypeReference baseTypeReference(int baseType, int dim) { + + if (dim == 0) { + switch (baseType) { + case (T_void) : + return new SingleTypeReference(VoidBinding.simpleName, 0); + case (T_boolean) : + return new SingleTypeReference(BooleanBinding.simpleName, 0); + case (T_char) : + return new SingleTypeReference(CharBinding.simpleName, 0); + case (T_float) : + return new SingleTypeReference(FloatBinding.simpleName, 0); + case (T_double) : + return new SingleTypeReference(DoubleBinding.simpleName, 0); + case (T_byte) : + return new SingleTypeReference(ByteBinding.simpleName, 0); + case (T_short) : + return new SingleTypeReference(ShortBinding.simpleName, 0); + case (T_int) : + return new SingleTypeReference(IntBinding.simpleName, 0); + default : //T_long + return new SingleTypeReference(LongBinding.simpleName, 0); + } + } + switch (baseType) { + case (T_void) : + return new ArrayTypeReference(VoidBinding.simpleName, dim, 0); + case (T_boolean) : + return new ArrayTypeReference(BooleanBinding.simpleName, dim, 0); + case (T_char) : + return new ArrayTypeReference(CharBinding.simpleName, dim, 0); + case (T_float) : + return new ArrayTypeReference(FloatBinding.simpleName, dim, 0); + case (T_double) : + return new ArrayTypeReference(DoubleBinding.simpleName, dim, 0); + case (T_byte) : + return new ArrayTypeReference(ByteBinding.simpleName, dim, 0); + case (T_short) : + return new ArrayTypeReference(ShortBinding.simpleName, dim, 0); + case (T_int) : + return new ArrayTypeReference(IntBinding.simpleName, dim, 0); + default : //T_long + return new ArrayTypeReference(LongBinding.simpleName, dim, 0); + } +} +public abstract TypeReference copyDims(int dim); +public int dimensions() { + return 0; +} +public abstract TypeBinding getTypeBinding(Scope scope); +/** + * @return char[][] + */ +public abstract char [][] getTypeName() ; +public boolean isTypeReference() { + return true; +} +public TypeBinding resolveType(BlockScope scope) { + // handle the error here + constant = NotAConstant; + if (binding != null) { // is a shared type reference which was already resolved + if (!binding.isValidBinding()) + return null; // already reported error + } else { + binding = getTypeBinding(scope); + if (!binding.isValidBinding()) { + scope.problemReporter().invalidType(this, binding); + return null; + } + if (isTypeUseDeprecated(binding, scope)) + scope.problemReporter().deprecatedType(binding, this); + } + return binding; +} +public abstract void traverse(IAbstractSyntaxTreeVisitor visitor, ClassScope classScope); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/UnaryExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/UnaryExpression.java new file mode 100644 index 0000000..8b0bbd2 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/UnaryExpression.java @@ -0,0 +1,288 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class UnaryExpression extends OperatorExpression { + + public Expression expression; + public Constant optimizedBooleanConstant; + + public UnaryExpression(Expression expression, int operator) { + this.expression = expression; + this.bits |= operator << OperatorSHIFT; // encode operator + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) { + return expression + .analyseCode(currentScope, flowContext, flowInfo) + .asNegatedCondition(); + } else { + return expression.analyseCode(currentScope, flowContext, flowInfo); + } + } + + public Constant conditionalConstant() { + return optimizedBooleanConstant == null ? constant : optimizedBooleanConstant; + } + + /** + * Code generation for an unary operation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + int pc = codeStream.position; + Label falseLabel, endifLabel; + if (constant != Constant.NotAConstant) { + // inlined value + if (valueRequired) { + codeStream.generateConstant(constant, implicitConversion); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + switch ((bits & OperatorMASK) >> OperatorSHIFT) { + case NOT : + switch (expression.implicitConversion >> 4) /* runtime type */ { + case T_boolean : + // ! + // Generate code for the condition + expression.generateOptimizedBoolean( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + valueRequired); + if (valueRequired) { + codeStream.iconst_0(); + if (falseLabel.hasForwardReferences()) { + codeStream.goto_(endifLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + falseLabel.place(); + codeStream.iconst_1(); + endifLabel.place(); + } + } else { // 6596: if (!(a && b)){} - must still place falseLabel + falseLabel.place(); + } + break; + } + break; + case TWIDDLE : + switch (expression.implicitConversion >> 4 /* runtime */ + ) { + case T_int : + // ~int + expression.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + codeStream.iconst_m1(); + codeStream.ixor(); + } + break; + case T_long : + expression.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + codeStream.ldc2_w(-1L); + codeStream.lxor(); + } + } + break; + case MINUS : + // - + if (constant != NotAConstant) { + if (valueRequired) { + switch (expression.implicitConversion >> 4 /* runtime */ + ) { + case T_int : + codeStream.generateInlinedValue(constant.intValue() * -1); + break; + case T_float : + codeStream.generateInlinedValue(constant.floatValue() * -1.0f); + break; + case T_long : + codeStream.generateInlinedValue(constant.longValue() * -1L); + break; + case T_double : + codeStream.generateInlinedValue(constant.doubleValue() * -1.0); + } + } + } else { + expression.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + switch (expression.implicitConversion >> 4 /* runtime type */ + ) { + case T_int : + codeStream.ineg(); + break; + case T_float : + codeStream.fneg(); + break; + case T_long : + codeStream.lneg(); + break; + case T_double : + codeStream.dneg(); + } + } + } + break; + case PLUS : + expression.generateCode(currentScope, codeStream, valueRequired); + } + if (valueRequired) { + codeStream.generateImplicitConversion(implicitConversion); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + /** + * Boolean operator code generation + * Optimized operations are: &&, ||, <, <=, >, >=, &, |, ^ + */ + public void generateOptimizedBoolean( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) { + super.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + return; + } + if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) { + expression.generateOptimizedBoolean( + currentScope, + codeStream, + falseLabel, + trueLabel, + valueRequired); + } else { + super.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + } + + public TypeBinding resolveType(BlockScope scope) { + TypeBinding expressionTb = expression.resolveType(scope); + if (expressionTb == null) { + constant = NotAConstant; + return null; + } + int expressionId = expressionTb.id; + if (expressionId > 15) { + constant = NotAConstant; + scope.problemReporter().invalidOperator(this, expressionTb); + return null; + } + + int tableId; + switch ((bits & OperatorMASK) >> OperatorSHIFT) { + case NOT : + tableId = AND_AND; + break; + case TWIDDLE : + tableId = LEFT_SHIFT; + break; + default : + tableId = MINUS; + } //+ and - cases + + // the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 <<0 + int result = ResolveTypeTables[tableId][(expressionId << 4) + expressionId]; + expression.implicitConversion = result >>> 12; + bits |= result & 0xF; + switch (result & 0xF) { // only switch on possible result type..... + case T_boolean : + this.typeBinding = BooleanBinding; + break; + case T_byte : + this.typeBinding = ByteBinding; + break; + case T_char : + this.typeBinding = CharBinding; + break; + case T_double : + this.typeBinding = DoubleBinding; + break; + case T_float : + this.typeBinding = FloatBinding; + break; + case T_int : + this.typeBinding = IntBinding; + break; + case T_long : + this.typeBinding = LongBinding; + break; + default : //error........ + constant = Constant.NotAConstant; + if (expressionId != T_undefined) + scope.problemReporter().invalidOperator(this, expressionTb); + return null; + } + // compute the constant when valid + if (expression.constant != Constant.NotAConstant) { + constant = + Constant.computeConstantOperation( + expression.constant, + expressionId, + (bits & OperatorMASK) >> OperatorSHIFT); + } else { + constant = Constant.NotAConstant; + if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) { + Constant cst = expression.conditionalConstant(); + if (cst.typeID() == T_boolean) + optimizedBooleanConstant = Constant.fromValue(!cst.booleanValue()); + } + } + return this.typeBinding; + } + + public String toStringExpressionNoParenthesis() { + return operatorToString() + " " + expression.toStringExpression(); //$NON-NLS-1$ + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + BlockScope blockScope) { + if (visitor.visit(this, blockScope)) { + expression.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/WhileStatement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/WhileStatement.java new file mode 100644 index 0000000..20377b0 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/WhileStatement.java @@ -0,0 +1,236 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.ast; + +import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class WhileStatement extends Statement { + + public Expression condition; + public Statement action; + private Label breakLabel, continueLabel; + int preCondInitStateIndex = -1; + int condIfTrueInitStateIndex = -1; + int mergedInitStateIndex = -1; + + public WhileStatement(Expression condition, Statement action, int s, int e) { + + this.condition = condition; + this.action = action; + sourceStart = s; + sourceEnd = e; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + breakLabel = new Label(); + continueLabel = new Label(); + + preCondInitStateIndex = + currentScope.methodScope().recordInitializationStates(flowInfo); + LoopingFlowContext condLoopContext; + FlowInfo postCondInfo = + condition.analyseCode( + currentScope, + (condLoopContext = + new LoopingFlowContext(flowContext, this, null, null, currentScope)), + flowInfo); + + LoopingFlowContext loopingContext; + if ((action == null) || action.isEmptyBlock()) { + condLoopContext.complainOnFinalAssignmentsInLoop(currentScope, postCondInfo); + if ((condition.constant != NotAConstant) + && (condition.constant.booleanValue() == true)) { + return FlowInfo.DeadEnd; + } else { + FlowInfo mergedInfo = postCondInfo.initsWhenFalse().unconditionalInits(); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + } else { + // in case the condition was inlined to false, record the fact that there is no way to reach any + // statement inside the looping action + loopingContext = + new LoopingFlowContext( + flowContext, + this, + breakLabel, + continueLabel, + currentScope); + FlowInfo actionInfo = + ((condition.constant != Constant.NotAConstant) + && (condition.constant.booleanValue() == false)) + ? FlowInfo.DeadEnd + : postCondInfo.initsWhenTrue().copy(); + + // for computing local var attributes + condIfTrueInitStateIndex = + currentScope.methodScope().recordInitializationStates( + postCondInfo.initsWhenTrue()); + + if (!actionInfo.complainIfUnreachable(action, currentScope)) { + actionInfo = action.analyseCode(currentScope, loopingContext, actionInfo); + } + + // code generation can be optimized when no need to continue in the loop + if (((actionInfo == FlowInfo.DeadEnd) || actionInfo.isFakeReachable()) + && ((loopingContext.initsOnContinue == FlowInfo.DeadEnd) + || loopingContext.initsOnContinue.isFakeReachable())) { + continueLabel = null; + } else { + condLoopContext.complainOnFinalAssignmentsInLoop(currentScope, postCondInfo); + loopingContext.complainOnFinalAssignmentsInLoop(currentScope, actionInfo); + } + } + + // infinite loop + FlowInfo mergedInfo; + if ((condition.constant != Constant.NotAConstant) + && (condition.constant.booleanValue() == true)) { + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates( + mergedInfo = loopingContext.initsOnBreak); + return mergedInfo; + } + + // end of loop: either condition false or break + mergedInfo = + postCondInfo.initsWhenFalse().unconditionalInits().mergedWith( + loopingContext.initsOnBreak); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + + /** + * While code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + breakLabel.codeStream = codeStream; + + // generate condition + if (continueLabel == null) { + // no need to reverse condition + if (condition.constant == NotAConstant) { + condition.generateOptimizedBoolean( + currentScope, + codeStream, + null, + breakLabel, + true); + } + } else { + continueLabel.codeStream = codeStream; + if (!(((condition.constant != NotAConstant) + && (condition.constant.booleanValue() == true)) + || (action == null) + || action.isEmptyBlock())) { + int jumpPC = codeStream.position; + codeStream.goto_(continueLabel); + codeStream.recordPositionsFrom(jumpPC, condition.sourceStart); + } + } + // generate the action + Label actionLabel; + (actionLabel = new Label(codeStream)).place(); + if (action != null) { + // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect + if (condIfTrueInitStateIndex != -1) { + // insert all locals initialized inside the condition into the action generated prior to the condition + codeStream.addDefinitelyAssignedVariables( + currentScope, + condIfTrueInitStateIndex); + } + action.generateCode(currentScope, codeStream); + // May loose some local variable initializations : affecting the local variable attributes + if (preCondInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + preCondInitStateIndex); + } + + } + // output condition and branch back to the beginning of the repeated action + if (continueLabel != null) { + continueLabel.place(); + condition.generateOptimizedBoolean( + currentScope, + codeStream, + actionLabel, + null, + true); + } + breakLabel.place(); + + // May loose some local variable initializations : affecting the local variable attributes + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public void resetStateForCodeGeneration() { + + this.breakLabel.resetStateForCodeGeneration(); + this.continueLabel.resetStateForCodeGeneration(); + } + + public void resolve(BlockScope scope) { + + TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding); + condition.implicitWidening(type, type); + if (action != null) + action.resolve(scope); + } + + public String toString(int tab) { + + String s = tabString(tab); + s = s + "while (" + condition.toStringExpression() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + if (action == null) + s = s + " {} ;"; //$NON-NLS-1$ + else if (action instanceof Block) + s = s + "\n" + action.toString(tab + 1); //$NON-NLS-1$ + else + s = s + " {\n" + action.toString(tab + 1) + "}"; //$NON-NLS-2$ //$NON-NLS-1$ + return s; + } + + public void traverse( + IAbstractSyntaxTreeVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + condition.traverse(visitor, blockScope); + if (action != null) + action.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/batch/ClasspathDirectory.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/batch/ClasspathDirectory.java new file mode 100644 index 0000000..18a7a1b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/batch/ClasspathDirectory.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.batch; + +import java.io.File; +import java.util.Hashtable; + +import net.sourceforge.phpdt.internal.compiler.classfmt.ClassFileReader; +import net.sourceforge.phpdt.internal.compiler.env.NameEnvironmentAnswer; + +public class ClasspathDirectory implements FileSystem.Classpath { + +String path; +Hashtable directoryCache; +String[] missingPackageHolder = new String[1]; +String encoding; +public int mode; // ability to only consider one kind of files (source vs. binaries), by default use both + +public static final int SOURCE = 1; +public static final int BINARY = 2; + +ClasspathDirectory(File directory, String encoding, int mode) { + this.mode = mode; + this.path = directory.getAbsolutePath(); + if (!path.endsWith(File.separator)) + this.path += File.separator; + this.directoryCache = new Hashtable(11); + this.encoding = encoding; +} + +ClasspathDirectory(File directory, String encoding) { + this(directory, encoding, SOURCE | BINARY); // by default consider both sources and binaries +} + +String[] directoryList(String qualifiedPackageName) { + String[] dirList = (String[]) directoryCache.get(qualifiedPackageName); + if (dirList == missingPackageHolder) return null; // package exists in another classpath directory or jar + if (dirList != null) return dirList; + + File dir = new File(path + qualifiedPackageName); + notFound : if (dir != null && dir.isDirectory()) { + // must protect against a case insensitive File call + // walk the qualifiedPackageName backwards looking for an uppercase character before the '/' + int index = qualifiedPackageName.length(); + int last = qualifiedPackageName.lastIndexOf(File.separatorChar); + while (--index > last && !Character.isUpperCase(qualifiedPackageName.charAt(index))) {} + if (index > last) { + if (last == -1) { + if (!doesFileExist(qualifiedPackageName, "")) //$NON-NLS-1$ + break notFound; + } else { + String packageName = qualifiedPackageName.substring(last + 1); + String parentPackage = qualifiedPackageName.substring(0, last); + if (!doesFileExist(packageName, parentPackage)) + break notFound; + } + } + if ((dirList = dir.list()) == null) + dirList = new String[0]; + directoryCache.put(qualifiedPackageName, dirList); + return dirList; + } + directoryCache.put(qualifiedPackageName, missingPackageHolder); + return null; +} +boolean doesFileExist(String fileName, String qualifiedPackageName) { + String[] dirList = directoryList(qualifiedPackageName); + if (dirList == null) return false; // most common case + + for (int i = dirList.length; --i >= 0;) + if (fileName.equals(dirList[i])) + return true; + return false; +} +public NameEnvironmentAnswer findClass(char[] typeName, String qualifiedPackageName, String qualifiedBinaryFileName) { + if (!isPackage(qualifiedPackageName)) return null; // most common case + + String fileName = new String(typeName); + boolean binaryExists = ((this.mode & BINARY) != 0) && doesFileExist(fileName + ".class", qualifiedPackageName); //$NON-NLS-1$ + boolean sourceExists = ((this.mode & SOURCE) != 0) && doesFileExist(fileName + ".java", qualifiedPackageName); //$NON-NLS-1$ + if (sourceExists) { + String fullSourcePath = path + qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - 6) + ".java"; //$NON-NLS-1$ + if (!binaryExists) + return new NameEnvironmentAnswer(new CompilationUnit(null, fullSourcePath, this.encoding)); + + String fullBinaryPath = path + qualifiedBinaryFileName; + long binaryModified = new File(fullBinaryPath).lastModified(); + long sourceModified = new File(fullSourcePath).lastModified(); + if (sourceModified > binaryModified) + return new NameEnvironmentAnswer(new CompilationUnit(null, fullSourcePath, this.encoding)); + } + if (binaryExists) { + try { + ClassFileReader reader = ClassFileReader.read(path + qualifiedBinaryFileName); + if (reader != null) return new NameEnvironmentAnswer(reader); + } catch (Exception e) {} // treat as if file is missing + } + return null; +} +public boolean isPackage(String qualifiedPackageName) { + return directoryList(qualifiedPackageName) != null; +} +public void reset() { + this.directoryCache = new Hashtable(11); +} +public String toString() { + return "ClasspathDirectory " + path; //$NON-NLS-1$ +} +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/batch/ClasspathJar.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/batch/ClasspathJar.java new file mode 100644 index 0000000..5ebcccf --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/batch/ClasspathJar.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.batch; + +import java.io.File; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import net.sourceforge.phpdt.internal.compiler.classfmt.ClassFileReader; +import net.sourceforge.phpdt.internal.compiler.env.NameEnvironmentAnswer; + +public class ClasspathJar implements FileSystem.Classpath { + +ZipFile zipFile; +Hashtable packageCache; +boolean closeZipFileAtEnd; + +public ClasspathJar(File file) throws IOException { + this(new ZipFile(file), true); +} +public ClasspathJar(ZipFile zipFile, boolean closeZipFileAtEnd) throws IOException { + this.zipFile = zipFile; + this.packageCache = null; + this.closeZipFileAtEnd = closeZipFileAtEnd; +} +public NameEnvironmentAnswer findClass(char[] typeName, String qualifiedPackageName, String qualifiedBinaryFileName) { + if (!isPackage(qualifiedPackageName)) return null; // most common case + + try { + ClassFileReader reader = ClassFileReader.read(zipFile, qualifiedBinaryFileName); + if (reader != null) return new NameEnvironmentAnswer(reader); + } catch (Exception e) {} // treat as if class file is missing + return null; +} +public boolean isPackage(String qualifiedPackageName) { + if (packageCache != null) + return packageCache.containsKey(qualifiedPackageName); + + this.packageCache = new Hashtable(41); + packageCache.put("", ""); //$NON-NLS-1$ //$NON-NLS-2$ + + nextEntry : for (Enumeration e = zipFile.entries(); e.hasMoreElements(); ) { + String fileName = ((ZipEntry) e.nextElement()).getName(); + + // add the package name & all of its parent packages + int last = fileName.lastIndexOf('/'); + while (last > 0) { + // extract the package name + String packageName = fileName.substring(0, last); + if (packageCache.containsKey(packageName)) + continue nextEntry; + packageCache.put(packageName, packageName); + last = packageName.lastIndexOf('/'); + } + } + return packageCache.containsKey(qualifiedPackageName); +} +public void reset() { + if (zipFile != null && closeZipFileAtEnd) { + try { zipFile.close(); } catch(IOException e) {} + } + this.packageCache = null; +} +public String toString() { + return "Classpath for jar file " + zipFile; //$NON-NLS-1$ +} +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/batch/CompilationUnit.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/batch/CompilationUnit.java new file mode 100644 index 0000000..56e3ae0 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/batch/CompilationUnit.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.batch; + +import java.io.File; +import java.io.IOException; + +import net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit; +import net.sourceforge.phpdt.internal.compiler.util.Util; + +public class CompilationUnit implements ICompilationUnit { + public char[] contents; + public char[] fileName; + public char[] mainTypeName; + String encoding; + +public CompilationUnit(char[] contents, String fileName, String encoding) { + this.contents = contents; + if (File.separator.equals("/")) { //$NON-NLS-1$ + if (fileName.indexOf("\\") != -1) { //$NON-NLS-1$ + fileName = fileName.replace('\\', File.separatorChar); + } + } else { + // the file separator is \ + if (fileName.indexOf('/') != -1) { + fileName = fileName.replace('/', File.separatorChar); + } + } + this.fileName = fileName.toCharArray(); + + int start = fileName.lastIndexOf("/") + 1; //$NON-NLS-1$ + if (start == 0 || start < fileName.lastIndexOf("\\")) //$NON-NLS-1$ + start = fileName.lastIndexOf("\\") + 1; //$NON-NLS-1$ + + int end = fileName.lastIndexOf("."); //$NON-NLS-1$ + if (end == -1) + end = fileName.length(); + + this.mainTypeName = fileName.substring(start, end).toCharArray(); + this.encoding = encoding; +} +public char[] getContents() { + if (contents != null) + return contents; // answer the cached source + + // otherwise retrieve it + try { + return Util.getFileCharContent(new File(new String(fileName)), encoding); + } catch (IOException e) { + } + return new char[0]; +} +public char[] getFileName() { + return fileName; +} +public char[] getMainTypeName() { + return mainTypeName; +} +public char[][] getPackageName() { + return null; +} +public String toString() { + return "CompilationUnit[" + new String(fileName) + "]"; //$NON-NLS-2$ //$NON-NLS-1$ +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/batch/FileFinder.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/batch/FileFinder.java new file mode 100644 index 0000000..0b842c8 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/batch/FileFinder.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.batch; + +import java.io.File; + +public class FileFinder { + private final int INITIAL_SIZE = 10; + public String[] resultFiles = new String[INITIAL_SIZE]; + public int counter = 0; +public void find(File f, String pattern, boolean verbose) { + if (verbose) { + System.out.println(Main.bind("scanning.start",f.getAbsolutePath())); //$NON-NLS-1$ + } + find0(f, pattern, verbose); + System.arraycopy(resultFiles, 0, (resultFiles = new String[counter]), 0, counter); +} +public void find0(File f, String pattern, boolean verbose) { + if (f.isDirectory()) { + String[] files = f.list(); + if (files == null) return; + for (int i = 0, max = files.length; i < max; i++) { + File current = new File(f, files[i]); + if (current.isDirectory()) { + find0(current, pattern, verbose); + } else { + if (current.getName().toUpperCase().endsWith(pattern)) { + int length; + if ((length = resultFiles.length) == counter) { + System.arraycopy(resultFiles, 0, (resultFiles = new String[length * 2]), 0, length); + } + resultFiles[counter++] = current.getAbsolutePath(); + if (verbose && (counter % 100) == 0) + System.out.print('.'); + } + } + } + } +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/batch/FileSystem.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/batch/FileSystem.java new file mode 100644 index 0000000..8c21815 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/batch/FileSystem.java @@ -0,0 +1,169 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.batch; + +import java.io.File; +import java.io.IOException; +import java.util.zip.ZipFile; + +import net.sourceforge.phpdt.internal.compiler.env.INameEnvironment; +import net.sourceforge.phpdt.internal.compiler.env.NameEnvironmentAnswer; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class FileSystem implements INameEnvironment { + Classpath[] classpaths; + String[] knownFileNames; + + interface Classpath { + NameEnvironmentAnswer findClass(char[] typeName, String qualifiedPackageName, String qualifiedBinaryFileName); + boolean isPackage(String qualifiedPackageName); + /** + * This method resets the environment. The resulting state is equivalent to + * a new name environment without creating a new object. + */ + void reset(); + } +/* + classPathNames is a collection is Strings representing the full path of each class path + initialFileNames is a collection is Strings, the trailing '.java' will be removed if its not already. +*/ + +public FileSystem(String[] classpathNames, String[] initialFileNames, String encoding) { + this(classpathNames, initialFileNames, encoding, null); +} +public FileSystem(String[] classpathNames, String[] initialFileNames, String encoding, int[] classpathDirectoryModes) { + int classpathSize = classpathNames.length; + classpaths = new Classpath[classpathSize]; + String[] pathNames = new String[classpathSize]; + int problemsOccured = 0; + for (int i = 0; i < classpathSize; i++) { + try { + File file = new File(convertPathSeparators(classpathNames[i])); + if (file.isDirectory()) { + if (file.exists()) { + if (classpathDirectoryModes == null){ + classpaths[i] = new ClasspathDirectory(file, encoding); + } else { + classpaths[i] = new ClasspathDirectory(file, encoding, classpathDirectoryModes[i]); + } + pathNames[i] = ((ClasspathDirectory) classpaths[i]).path; + } + } else if (classpathNames[i].endsWith(".jar") | (classpathNames[i].endsWith(".zip"))) { //$NON-NLS-2$ //$NON-NLS-1$ + classpaths[i] = this.getClasspathJar(file); // will throw an IOException if file does not exist + pathNames[i] = classpathNames[i].substring(0, classpathNames[i].lastIndexOf('.')); + } + } catch (IOException e) { + classpaths[i] = null; + } + if (classpaths[i] == null) + problemsOccured++; + } + if (problemsOccured > 0) { + Classpath[] newPaths = new Classpath[classpathSize - problemsOccured]; + String[] newNames = new String[classpathSize - problemsOccured]; + for (int i = 0, current = 0; i < classpathSize; i++) + if (classpaths[i] != null) { + newPaths[current] = classpaths[i]; + newNames[current++] = pathNames[i]; + } + classpathSize = newPaths.length; + classpaths = newPaths; + pathNames = newNames; + } + + knownFileNames = new String[initialFileNames.length]; + for (int i = initialFileNames.length; --i >= 0;) { + String fileName = initialFileNames[i]; + String matchingPathName = null; + if (fileName.lastIndexOf(".") != -1) //$NON-NLS-1$ + fileName = fileName.substring(0, fileName.lastIndexOf('.')); // remove trailing ".java" + + fileName = convertPathSeparators(fileName); + for (int j = 0; j < classpathSize; j++) + if (fileName.startsWith(pathNames[j])) + matchingPathName = pathNames[j]; + if (matchingPathName == null) + knownFileNames[i] = fileName; // leave as is... + else + knownFileNames[i] = fileName.substring(matchingPathName.length()); + } +} +public void cleanup() { + for (int i = 0, max = classpaths.length; i < max; i++) + classpaths[i].reset(); +} +private String convertPathSeparators(String path) { + return File.separatorChar == '/' + ? path.replace('\\', '/') + : path.replace('/', '\\'); +} +private NameEnvironmentAnswer findClass(String qualifiedTypeName, char[] typeName){ + for (int i = 0, length = knownFileNames.length; i < length; i++) + if (qualifiedTypeName.equals(knownFileNames[i])) + return null; // looking for a file which we know was provided at the beginning of the compilation + + String qualifiedBinaryFileName = qualifiedTypeName + ".class"; //$NON-NLS-1$ + String qualifiedPackageName = + qualifiedTypeName.length() == typeName.length + ? "" //$NON-NLS-1$ + : qualifiedBinaryFileName.substring(0, qualifiedTypeName.length() - typeName.length - 1); + String qp2 = File.separatorChar == '/' ? qualifiedPackageName : qualifiedPackageName.replace('/', File.separatorChar); + if (qualifiedPackageName == qp2) { + for (int i = 0, length = classpaths.length; i < length; i++) { + NameEnvironmentAnswer answer = classpaths[i].findClass(typeName, qualifiedPackageName, qualifiedBinaryFileName); + if (answer != null) return answer; + } + } else { + String qb2 = qualifiedBinaryFileName.replace('/', File.separatorChar); + for (int i = 0, length = classpaths.length; i < length; i++) { + Classpath p = classpaths[i]; + NameEnvironmentAnswer answer = (p instanceof ClasspathJar) + ? p.findClass(typeName, qualifiedPackageName, qualifiedBinaryFileName) + : p.findClass(typeName, qp2, qb2); + if (answer != null) return answer; + } + } + return null; +} +public NameEnvironmentAnswer findType(char[][] compoundName) { + if (compoundName != null) + return findClass( + new String(CharOperation.concatWith(compoundName, '/')), + compoundName[compoundName.length - 1]); + return null; +} +public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) { + if (typeName != null) + return findClass( + new String(CharOperation.concatWith(packageName, typeName, '/')), + typeName); + return null; +} +public ClasspathJar getClasspathJar(File file) throws IOException { + return new ClasspathJar(new ZipFile(file), true); +} +public boolean isPackage(char[][] compoundName, char[] packageName) { + String qualifiedPackageName = new String(CharOperation.concatWith(compoundName, packageName, '/')); + String qp2 = File.separatorChar == '/' ? qualifiedPackageName : qualifiedPackageName.replace('/', File.separatorChar); + if (qualifiedPackageName == qp2) { + for (int i = 0, length = classpaths.length; i < length; i++) + if (classpaths[i].isPackage(qualifiedPackageName)) + return true; + } else { + for (int i = 0, length = classpaths.length; i < length; i++) { + Classpath p = classpaths[i]; + if ((p instanceof ClasspathJar) ? p.isPackage(qualifiedPackageName) : p.isPackage(qp2)) + return true; + } + } + return false; +} +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/batch/Main.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/batch/Main.java new file mode 100644 index 0000000..f833f8b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/batch/Main.java @@ -0,0 +1,1288 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.batch; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Locale; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.StringTokenizer; + +import net.sourceforge.phpdt.core.compiler.InvalidInputException; +import net.sourceforge.phpdt.core.compiler.IProblem; +import net.sourceforge.phpdt.internal.compiler.ClassFile; +import net.sourceforge.phpdt.internal.compiler.CompilationResult; +import net.sourceforge.phpdt.internal.compiler.Compiler; +import net.sourceforge.phpdt.internal.compiler.ICompilerRequestor; +import net.sourceforge.phpdt.internal.compiler.IErrorHandlingPolicy; +import net.sourceforge.phpdt.internal.compiler.IProblemFactory; +import net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit; +import net.sourceforge.phpdt.internal.compiler.env.INameEnvironment; +import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions; +import net.sourceforge.phpdt.internal.compiler.problem.DefaultProblem; +import net.sourceforge.phpdt.internal.compiler.problem.DefaultProblemFactory; +import net.sourceforge.phpdt.internal.compiler.problem.ProblemSeverities; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; +import net.sourceforge.phpdt.internal.compiler.util.HashtableOfObject; + +public class Main implements ProblemSeverities { + + public boolean noWarn = false; + + public PrintWriter out; + public boolean systemExitWhenFinished = true; + public boolean proceedOnError = false; + + public boolean verbose = false; + public boolean produceRefInfo = false; + public boolean timer = false; + public boolean showProgress = false; + public long time = 0; + public long lineCount; + public boolean generatePackagesStructure; + + public Hashtable options; + public String[] filenames; + public String[] encodings; + public String[] classpaths; + public String destinationPath; + public String log; + public int repetitions; + public int globalProblemsCount; + public int globalErrorsCount; + public int globalWarningsCount; + public int exportedClassFilesCounter; + + public static final char[] CLASS_FILE_EXTENSION = ".class".toCharArray(); //$NON-NLS-1$ + public final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$ + public final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$ + + /* Bundle containing messages */ + public static ResourceBundle bundle; + public final static String bundleName = + "org.eclipse.jdt.internal.compiler.batch.messages"; //$NON-NLS-1$ + + static { + relocalize(); + } + + public boolean proceed = true; + + public Main(PrintWriter writer, boolean systemExitWhenFinished) { + + this.out = writer; + this.systemExitWhenFinished = systemExitWhenFinished; + exportedClassFilesCounter = 0; + options = new Hashtable(); + options.put( + CompilerOptions.OPTION_LocalVariableAttribute, + CompilerOptions.DO_NOT_GENERATE); + options.put( + CompilerOptions.OPTION_LineNumberAttribute, + CompilerOptions.DO_NOT_GENERATE); + options.put( + CompilerOptions.OPTION_SourceFileAttribute, + CompilerOptions.DO_NOT_GENERATE); + options.put( + CompilerOptions.OPTION_PreserveUnusedLocal, + CompilerOptions.OPTIMIZE_OUT); + options.put( + CompilerOptions.OPTION_ReportUnreachableCode, + CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportInvalidImport, CompilerOptions.ERROR); + options.put( + CompilerOptions.OPTION_ReportOverridingPackageDefaultMethod, + CompilerOptions.WARNING); + options.put( + CompilerOptions.OPTION_ReportMethodWithConstructorName, + CompilerOptions.WARNING); + options.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING); + options.put( + CompilerOptions.OPTION_ReportHiddenCatchBlock, + CompilerOptions.WARNING); + options.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.IGNORE); + options.put( + CompilerOptions.OPTION_ReportUnusedParameter, + CompilerOptions.IGNORE); + options.put( + CompilerOptions.OPTION_ReportSyntheticAccessEmulation, + CompilerOptions.IGNORE); + options.put( + CompilerOptions.OPTION_ReportNonExternalizedStringLiteral, + CompilerOptions.IGNORE); + options.put( + CompilerOptions.OPTION_ReportAssertIdentifier, + CompilerOptions.IGNORE); + options.put( + CompilerOptions.OPTION_Compliance, + CompilerOptions.VERSION_1_3); + options.put( + CompilerOptions.OPTION_Source, + CompilerOptions.VERSION_1_3); + options.put( + CompilerOptions.OPTION_TargetPlatform, + CompilerOptions.VERSION_1_1); + } + + /* + * Low-level API performing the actual compilation + */ + public boolean compile(String[] argv) { + + // decode command line arguments + try { + configure(argv); + if (proceed) { + if (showProgress) + out.print(Main.bind("progress.compiling")); //$NON-NLS-1$ + for (int i = 0; i < repetitions; i++) { + globalProblemsCount = 0; + globalErrorsCount = 0; + globalWarningsCount = 0; + lineCount = 0; + + if (repetitions > 1) { + out.flush(); + out.println( + Main.bind( + "compile.repetition", //$NON-NLS-1$ + String.valueOf(i + 1), + String.valueOf(repetitions))); + } + long startTime = System.currentTimeMillis(); + // request compilation + performCompilation(); + if (timer) { + + time = System.currentTimeMillis() - startTime; + if (lineCount != 0) { + out.println( + Main.bind( + "compile.instantTime", //$NON-NLS-1$ + new String[] { + String.valueOf(lineCount), + String.valueOf(time), + String.valueOf((((int) ((lineCount * 10000.0) / time)) / 10.0))})); + } else { + out.println(Main.bind("compile.totalTime", String.valueOf(time))); //$NON-NLS-1$ + } + } + if (globalProblemsCount > 0) { + if (globalProblemsCount == 1) { + out.print(Main.bind("compile.oneProblem")); //$NON-NLS-1$ + } else { + out.print( + Main.bind("compile.severalProblems", String.valueOf(globalProblemsCount))); //$NON-NLS-1$ + } + out.print(" ("); //$NON-NLS-1$ + if (globalErrorsCount > 0) { + if (globalErrorsCount == 1) { + out.print(Main.bind("compile.oneError")); //$NON-NLS-1$ + } else { + out.print( + Main.bind("compile.severalErrors", String.valueOf(globalErrorsCount))); //$NON-NLS-1$ + } + } + if (globalWarningsCount > 0) { + if (globalErrorsCount > 0) { + out.print(", "); //$NON-NLS-1$ + } + if (globalWarningsCount == 1) { + out.print(Main.bind("compile.oneWarning")); //$NON-NLS-1$ + } else { + out.print( + Main.bind("compile.severalWarnings", String.valueOf(globalWarningsCount))); //$NON-NLS-1$ + } + } + out.println(")"); //$NON-NLS-1$ + } + if (exportedClassFilesCounter != 0 + && (this.showProgress || this.timer || this.verbose)) { + if (exportedClassFilesCounter == 1) { + out.print(Main.bind("compile.oneClassFileGenerated")); //$NON-NLS-1$ + } else { + out.print( + Main.bind( + "compile.severalClassFilesGenerated", //$NON-NLS-1$ + String.valueOf(exportedClassFilesCounter))); + } + } + } + if (showProgress) + System.out.println(); + } + if (systemExitWhenFinished) { + out.flush(); + System.exit(globalErrorsCount > 0 ? -1 : 0); + } + } catch (InvalidInputException e) { + out.println(e.getMessage()); + out.println("------------------------"); //$NON-NLS-1$ + printUsage(); + if (systemExitWhenFinished) { + System.exit(-1); + } + } catch (ThreadDeath e) { // do not stop this one + throw e; + } catch (Throwable e) { // internal compiler error + if (systemExitWhenFinished) { + out.flush(); + if (this.log != null) { + out.close(); + } + System.exit(-1); + } + //e.printStackTrace(); + } finally { + out.flush(); + if (this.log != null) { + out.close(); + } + } + if (globalErrorsCount == 0){ + return true; + } else { + return false; + } + } + + /* + * Internal IDE API + */ + public static boolean compile(String commandLine) { + + return compile(commandLine, new PrintWriter(System.out)); + } + + /* + * Internal IDE API for test harness purpose + */ + public static boolean compile(String commandLine, PrintWriter writer) { + + return new Main(writer, false).compile(tokenize(commandLine)); + } + + public static String[] tokenize(String commandLine) { + + int count = 0; + String[] arguments = new String[10]; + StringTokenizer tokenizer = new StringTokenizer(commandLine, " \"", true); //$NON-NLS-1$ + String token = "", lastToken; //$NON-NLS-1$ + boolean insideQuotes = false; + boolean startNewToken = true; + + // take care to quotes on the command line + // 'xxx "aaa bbb";ccc yyy' ---> {"xxx", "aaa bbb;ccc", "yyy" } + // 'xxx "aaa bbb;ccc" yyy' ---> {"xxx", "aaa bbb;ccc", "yyy" } + // 'xxx "aaa bbb";"ccc" yyy' ---> {"xxx", "aaa bbb;ccc", "yyy" } + // 'xxx/"aaa bbb";"ccc" yyy' ---> {"xxx/aaa bbb;ccc", "yyy" } + while (tokenizer.hasMoreTokens()) { + lastToken = token; + token = tokenizer.nextToken(); + + if (token.equals(" ")) { //$NON-NLS-1$ + if (insideQuotes) { + arguments[count - 1] += token; + startNewToken = false; + } else { + startNewToken = true; + } + } else if (token.equals("\"")) { //$NON-NLS-1$ + if (!insideQuotes && startNewToken) { //$NON-NLS-1$ + if (count == arguments.length) + System.arraycopy(arguments, 0, (arguments = new String[count * 2]), 0, count); + arguments[count++] = ""; //$NON-NLS-1$ + } + insideQuotes = !insideQuotes; + startNewToken = false; + } else { + if (insideQuotes) { + arguments[count - 1] += token; + } else { + if (token.length() > 0 && !startNewToken) { + arguments[count - 1] += token; + } else { + if (count == arguments.length) + System.arraycopy(arguments, 0, (arguments = new String[count * 2]), 0, count); + arguments[count++] = token; + } + } + startNewToken = false; + } + } + System.arraycopy(arguments, 0, arguments = new String[count], 0, count); + return arguments; + } + + /* + Decode the command line arguments + */ + public void configure(String[] argv) throws InvalidInputException { + + if ((argv == null) || (argv.length == 0)) + throw new InvalidInputException(Main.bind("configure.noSourceFile")); //$NON-NLS-1$ + final int InsideClasspath = 1; + final int InsideDestinationPath = 2; + final int TargetSetting = 4; + final int InsideLog = 8; + final int InsideRepetition = 16; + final int InsideSource = 32; + final int InsideDefaultEncoding = 64; + final int Default = 0; + int DEFAULT_SIZE_CLASSPATH = 4; + boolean warnOptionInUse = false; + boolean noWarnOptionInUse = false; + int pathCount = 0; + int index = -1, filesCount = 0, argCount = argv.length; + int mode = Default; + repetitions = 0; + boolean versionIDRequired = false; + boolean printUsageRequired = false; + + boolean didSpecifyCompliance = false; + boolean didSpecifySourceLevel = false; + boolean didSpecifyDefaultEncoding = false; + boolean didSpecifyTarget = false; + + String customEncoding = null; + String currentArg = ""; //$NON-NLS-1$ + + while (++index < argCount) { + + if (customEncoding != null) { + throw new InvalidInputException( + Main.bind("configure.unexpectedCustomEncoding", currentArg, customEncoding)); //$NON-NLS-1$ + } + + currentArg = argv[index].trim(); + + customEncoding = null; + if (currentArg.endsWith("]")) { //$NON-NLS-1$ + // look for encoding specification + int encodingStart = currentArg.indexOf('[') + 1; + int encodingEnd = currentArg.length() - 1; + if (encodingStart >= 1) { + if (encodingStart < encodingEnd) { + customEncoding = currentArg.substring(encodingStart, encodingEnd); + try { // ensure encoding is supported + new InputStreamReader(new ByteArrayInputStream(new byte[0]), customEncoding); + } catch (UnsupportedEncodingException e) { + throw new InvalidInputException( + Main.bind("configure.unsupportedEncoding", customEncoding)); //$NON-NLS-1$ + } + } + currentArg = currentArg.substring(0, encodingStart - 1); + } + } + + if (currentArg.endsWith(".java")) { //$NON-NLS-1$ + if (filenames == null) { + filenames = new String[argCount - index]; + encodings = new String[argCount - index]; + } else if (filesCount == filenames.length) { + int length = filenames.length; + System.arraycopy( + filenames, + 0, + (filenames = new String[length + argCount - index]), + 0, + length); + System.arraycopy( + encodings, + 0, + (encodings = new String[length + argCount - index]), + 0, + length); + } + filenames[filesCount] = currentArg; + encodings[filesCount++] = customEncoding; + customEncoding = null; + mode = Default; + continue; + } + if (currentArg.equals("-log")) { //$NON-NLS-1$ + if (log != null) + throw new InvalidInputException( + Main.bind("configure.duplicateLog", currentArg)); //$NON-NLS-1$ + mode = InsideLog; + continue; + } + if (currentArg.equals("-repeat")) { //$NON-NLS-1$ + if (repetitions > 0) + throw new InvalidInputException( + Main.bind("configure.duplicateRepeat", currentArg)); //$NON-NLS-1$ + mode = InsideRepetition; + continue; + } + if (currentArg.equals("-source")) { //$NON-NLS-1$ + mode = InsideSource; + didSpecifySourceLevel = true; + continue; + } + if (currentArg.equals("-encoding")) { //$NON-NLS-1$ + mode = InsideDefaultEncoding; + continue; + } + if (currentArg.equals("-1.3")) { //$NON-NLS-1$ + if (didSpecifyCompliance) { + throw new InvalidInputException( + Main.bind("configure.duplicateCompliance", currentArg));//$NON-NLS-1$ + } + didSpecifyCompliance = true; + options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_3); + mode = Default; + continue; + } + if (currentArg.equals("-1.4")) { //$NON-NLS-1$ + if (didSpecifyCompliance) { + throw new InvalidInputException( + Main.bind("configure.duplicateCompliance", currentArg)); //$NON-NLS-1$ + } + didSpecifyCompliance = true; + options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_4); + mode = Default; + continue; + } + if (currentArg.equals("-d")) { //$NON-NLS-1$ + if (destinationPath != null) + throw new InvalidInputException( + Main.bind("configure.duplicateOutputPath", currentArg)); //$NON-NLS-1$ + mode = InsideDestinationPath; + generatePackagesStructure = true; + continue; + } + if (currentArg.equals("-classpath") //$NON-NLS-1$ + || currentArg.equals("-cp")) { //$NON-NLS-1$ //$NON-NLS-2$ + if (pathCount > 0) + throw new InvalidInputException( + Main.bind("configure.duplicateClasspath", currentArg)); //$NON-NLS-1$ + classpaths = new String[DEFAULT_SIZE_CLASSPATH]; + mode = InsideClasspath; + continue; + } + if (currentArg.equals("-progress")) { //$NON-NLS-1$ + mode = Default; + showProgress = true; + continue; + } + if (currentArg.equals("-proceedOnError")) { //$NON-NLS-1$ + mode = Default; + proceedOnError = true; + continue; + } + if (currentArg.equals("-time")) { //$NON-NLS-1$ + mode = Default; + timer = true; + continue; + } + if (currentArg.equals("-version") //$NON-NLS-1$ + || currentArg.equals("-v")) { //$NON-NLS-1$ //$NON-NLS-2$ + versionIDRequired = true; + continue; + } + if ("-deprecation".equals(currentArg)) { //$NON-NLS-1$ + warnOptionInUse = true; + if (noWarnOptionInUse) + throw new InvalidInputException( + Main.bind("configure.duplicateWarningConfiguration")); //$NON-NLS-1$ + options.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING); + continue; + } + if (currentArg.equals("-help")) { //$NON-NLS-1$ + printUsageRequired = true; + continue; + } + if (currentArg.equals("-noImportError")) { //$NON-NLS-1$ + mode = Default; + options.put( + CompilerOptions.OPTION_ReportInvalidImport, + CompilerOptions.WARNING); + continue; + } + if (currentArg.equals("-noExit")) { //$NON-NLS-1$ + mode = Default; + systemExitWhenFinished = false; + continue; + } + if (currentArg.equals("-verbose")) { //$NON-NLS-1$ + mode = Default; + verbose = true; + continue; + } + if (currentArg.equals("-referenceInfo")) { //$NON-NLS-1$ + mode = Default; + produceRefInfo = true; + continue; + } + if (currentArg.startsWith("-g")) { //$NON-NLS-1$ + mode = Default; + String debugOption = currentArg; + int length = currentArg.length(); + if (length == 2) { + options.put( + CompilerOptions.OPTION_LocalVariableAttribute, + CompilerOptions.GENERATE); + options.put( + CompilerOptions.OPTION_LineNumberAttribute, + CompilerOptions.GENERATE); + options.put( + CompilerOptions.OPTION_SourceFileAttribute, + CompilerOptions.GENERATE); + continue; + } + if (length > 3) { + options.put( + CompilerOptions.OPTION_LocalVariableAttribute, + CompilerOptions.DO_NOT_GENERATE); + options.put( + CompilerOptions.OPTION_LineNumberAttribute, + CompilerOptions.DO_NOT_GENERATE); + options.put( + CompilerOptions.OPTION_SourceFileAttribute, + CompilerOptions.DO_NOT_GENERATE); + if (length == 7 && debugOption.equals("-g:none")) //$NON-NLS-1$ + continue; + StringTokenizer tokenizer = + new StringTokenizer(debugOption.substring(3, debugOption.length()), ","); //$NON-NLS-1$ + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + if (token.equals("vars")) { //$NON-NLS-1$ + options.put( + CompilerOptions.OPTION_LocalVariableAttribute, + CompilerOptions.GENERATE); + } else if (token.equals("lines")) { //$NON-NLS-1$ + options.put( + CompilerOptions.OPTION_LineNumberAttribute, + CompilerOptions.GENERATE); + } else if (token.equals("source")) { //$NON-NLS-1$ + options.put( + CompilerOptions.OPTION_SourceFileAttribute, + CompilerOptions.GENERATE); + } else { + throw new InvalidInputException( + Main.bind("configure.invalidDebugOption", debugOption)); //$NON-NLS-1$ + //$NON-NLS-1$ + } + } + continue; + } + throw new InvalidInputException( + Main.bind("configure.invalidDebugOption", debugOption)); //$NON-NLS-1$ + } + if (currentArg.startsWith("-nowarn")) { //$NON-NLS-1$ + noWarnOptionInUse = true; + noWarn = true; + if (warnOptionInUse) + throw new InvalidInputException( + Main.bind("configure.duplicateWarningConfiguration")); //$NON-NLS-1$ + mode = Default; + continue; + } + if (currentArg.startsWith("-warn")) { //$NON-NLS-1$ + warnOptionInUse = true; + if (noWarnOptionInUse) + throw new InvalidInputException( + Main.bind("configure.duplicateWarningConfiguration")); //$NON-NLS-1$ + mode = Default; + String warningOption = currentArg; + int length = currentArg.length(); + if (length == 10 && warningOption.equals("-warn:none")) { //$NON-NLS-1$ + noWarn = true; + continue; + } + if (length < 6) + throw new InvalidInputException( + Main.bind("configure.invalidWarningConfiguration", warningOption)); //$NON-NLS-1$ + StringTokenizer tokenizer = + new StringTokenizer(warningOption.substring(6, warningOption.length()), ","); //$NON-NLS-1$ + int tokenCounter = 0; + + options.put( + CompilerOptions.OPTION_ReportOverridingPackageDefaultMethod, + CompilerOptions.IGNORE); + options.put( + CompilerOptions.OPTION_ReportMethodWithConstructorName, + CompilerOptions.IGNORE); + options.put( + CompilerOptions.OPTION_ReportDeprecation, + CompilerOptions.IGNORE); + options.put( + CompilerOptions.OPTION_ReportHiddenCatchBlock, + CompilerOptions.IGNORE); + options.put( + CompilerOptions.OPTION_ReportUnusedLocal, + CompilerOptions.IGNORE); + options.put( + CompilerOptions.OPTION_ReportUnusedParameter, + CompilerOptions.IGNORE); + options.put( + CompilerOptions.OPTION_ReportSyntheticAccessEmulation, + CompilerOptions.IGNORE); + options.put( + CompilerOptions.OPTION_ReportNonExternalizedStringLiteral, + CompilerOptions.IGNORE); + options.put( + CompilerOptions.OPTION_ReportAssertIdentifier, + CompilerOptions.IGNORE); + options.put( + CompilerOptions.OPTION_ReportUnusedImport, + CompilerOptions.IGNORE); + + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + tokenCounter++; + if (token.equals("constructorName")) { //$NON-NLS-1$ + options.put( + CompilerOptions.OPTION_ReportMethodWithConstructorName, + CompilerOptions.WARNING); + } else if (token.equals("packageDefaultMethod")) { //$NON-NLS-1$ + options.put( + CompilerOptions.OPTION_ReportOverridingPackageDefaultMethod, + CompilerOptions.WARNING); + } else if (token.equals("maskedCatchBlocks")) { //$NON-NLS-1$ + options.put( + CompilerOptions.OPTION_ReportHiddenCatchBlock, + CompilerOptions.WARNING); + } else if (token.equals("deprecation")) { //$NON-NLS-1$ + options.put( + CompilerOptions.OPTION_ReportDeprecation, + CompilerOptions.WARNING); + } else if (token.equals("unusedLocals")) { //$NON-NLS-1$ + options.put( + CompilerOptions.OPTION_ReportUnusedLocal, + CompilerOptions.WARNING); + } else if (token.equals("unusedArguments")) { //$NON-NLS-1$ + options.put( + CompilerOptions.OPTION_ReportUnusedParameter, + CompilerOptions.WARNING); + } else if (token.equals("unusedImports")) { //$NON-NLS-1$ + options.put( + CompilerOptions.OPTION_ReportUnusedImport, + CompilerOptions.WARNING); + } else if (token.equals("syntheticAccess")) { //$NON-NLS-1$ + options.put( + CompilerOptions.OPTION_ReportSyntheticAccessEmulation, + CompilerOptions.WARNING); + } else if (token.equals("nls")) { //$NON-NLS-1$ + options.put( + CompilerOptions.OPTION_ReportNonExternalizedStringLiteral, + CompilerOptions.WARNING); + } else if (token.equals("assertIdentifier")) { //$NON-NLS-1$ + options.put( + CompilerOptions.OPTION_ReportAssertIdentifier, + CompilerOptions.WARNING); + } else { + throw new InvalidInputException(Main.bind("configure.invalidWarning", token)); //$NON-NLS-1$ + } + } + if (tokenCounter == 0) + throw new InvalidInputException( + Main.bind("configure.invalidWarningOption", currentArg)); //$NON-NLS-1$ + continue; + } + if (currentArg.equals("-target")) { //$NON-NLS-1$ + didSpecifyTarget = true; + mode = TargetSetting; + continue; + } + if (currentArg.equals("-preserveAllLocals")) { //$NON-NLS-1$ + options.put( + CompilerOptions.OPTION_PreserveUnusedLocal, + CompilerOptions.PRESERVE); + continue; + } + if (mode == TargetSetting) { + if (currentArg.equals("1.1")) { //$NON-NLS-1$ + options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_1); + } else if (currentArg.equals("1.2")) { //$NON-NLS-1$ + options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_2); + } else if (currentArg.equals("1.3")) { //$NON-NLS-1$ + options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_3); + } else if (currentArg.equals("1.4")) { //$NON-NLS-1$ + options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4); + } else { + throw new InvalidInputException(Main.bind("configure.targetJDK", currentArg)); //$NON-NLS-1$ + } + mode = Default; + continue; + } + if (mode == InsideLog) { + log = currentArg; + mode = Default; + continue; + } + if (mode == InsideRepetition) { + try { + repetitions = Integer.parseInt(currentArg); + if (repetitions <= 0) { + throw new InvalidInputException(Main.bind("configure.repetition", currentArg)); //$NON-NLS-1$ + } + } catch (NumberFormatException e) { + throw new InvalidInputException(Main.bind("configure.repetition", currentArg)); //$NON-NLS-1$ + } + mode = Default; + continue; + } + if (mode == InsideSource) { + if (currentArg.equals("1.3")) { //$NON-NLS-1$ + options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_3); + } else if (currentArg.equals("1.4")) { //$NON-NLS-1$ + options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_4); + } else { + throw new InvalidInputException(Main.bind("configure.source", currentArg)); //$NON-NLS-1$ + } + mode = Default; + continue; + } + if (mode == InsideDefaultEncoding) { + if (didSpecifyDefaultEncoding) { + throw new InvalidInputException( + Main.bind("configure.duplicateDefaultEncoding", currentArg)); //$NON-NLS-1$ + } + try { // ensure encoding is supported + new InputStreamReader(new ByteArrayInputStream(new byte[0]), currentArg); + } catch (UnsupportedEncodingException e) { + throw new InvalidInputException( + Main.bind("configure.unsupportedEncoding", currentArg)); //$NON-NLS-1$ + } + options.put(CompilerOptions.OPTION_Encoding, currentArg); + didSpecifyDefaultEncoding = true; + mode = Default; + continue; + } + if (mode == InsideDestinationPath) { + destinationPath = currentArg; + mode = Default; + continue; + } + if (mode == InsideClasspath) { + StringTokenizer tokenizer = new StringTokenizer(currentArg, File.pathSeparator); + while (tokenizer.hasMoreTokens()) { + int length; + if ((length = classpaths.length) <= pathCount) { + System.arraycopy( + classpaths, + 0, + (classpaths = new String[length * 2]), + 0, + length); + } + classpaths[pathCount++] = tokenizer.nextToken(); + } + mode = Default; + continue; + } + //default is input directory + currentArg = currentArg.replace('/', File.separatorChar); + if (currentArg.endsWith(File.separator)) + currentArg = + currentArg.substring(0, currentArg.length() - File.separator.length()); + File dir = new File(currentArg); + if (!dir.isDirectory()) + throw new InvalidInputException( + Main.bind("configure.directoryNotExist", currentArg)); //$NON-NLS-1$ + FileFinder finder = new FileFinder(); + try { + finder.find(dir, ".JAVA", verbose); //$NON-NLS-1$ + } catch (Exception e) { + throw new InvalidInputException(Main.bind("configure.IOError", currentArg)); //$NON-NLS-1$ + } + if (filenames != null) { + // some source files were specified explicitly + String results[] = finder.resultFiles; + int length = results.length; + System.arraycopy( + filenames, + 0, + (filenames = new String[length + filesCount]), + 0, + filesCount); + System.arraycopy( + encodings, + 0, + (encodings = new String[length + filesCount]), + 0, + filesCount); + System.arraycopy(results, 0, filenames, filesCount, length); + for (int i = 0; i < length; i++) { + encodings[filesCount + i] = customEncoding; + } + filesCount += length; + customEncoding = null; + } else { + filenames = finder.resultFiles; + filesCount = filenames.length; + encodings = new String[filesCount]; + for (int i = 0; i < filesCount; i++) { + encodings[i] = customEncoding; + } + customEncoding = null; + } + mode = Default; + continue; + } + + if (noWarn) { + // filter options which are related to the assist component + Object[] entries = options.entrySet().toArray(); + for (int i = 0, max = entries.length; i < max; i++) { + Map.Entry entry = (Map.Entry) entries[i]; + if (!(entry.getKey() instanceof String)) + continue; + if (!(entry.getValue() instanceof String)) + continue; + if (((String) entry.getValue()).equals(CompilerOptions.WARNING)) { + options.put((String) entry.getKey(), CompilerOptions.IGNORE); + } + } + } + /* + * Standalone options + */ + if (versionIDRequired) { + out.println(Main.bind("configure.version", Main.bind("compiler.version"))); //$NON-NLS-1$ //$NON-NLS-2$ + out.println(); + proceed = false; + return; + } + + if (printUsageRequired) { + printUsage(); + proceed = false; + return; + } + + if (filesCount != 0) + System.arraycopy( + filenames, + 0, + (filenames = new String[filesCount]), + 0, + filesCount); + if (pathCount == 0) { + String classProp = System.getProperty("DEFAULT_CLASSPATH"); //$NON-NLS-1$ + if ((classProp == null) || (classProp.length() == 0)) { + out.println(Main.bind("configure.noClasspath")); //$NON-NLS-1$ + classProp = "."; //$NON-NLS-1$ + } + StringTokenizer tokenizer = new StringTokenizer(classProp, File.pathSeparator); + classpaths = new String[tokenizer.countTokens()]; + while (tokenizer.hasMoreTokens()) { + classpaths[pathCount++] = tokenizer.nextToken(); + } + } + + if (classpaths == null) + classpaths = new String[0]; + System.arraycopy( + classpaths, + 0, + (classpaths = new String[pathCount]), + 0, + pathCount); + for (int i = 0, max = classpaths.length; i < max; i++) { + File file = new File(classpaths[i]); + if (!file.exists()) // signal missing classpath entry file + out.println(Main.bind("configure.incorrectClasspath", classpaths[i])); //$NON-NLS-1$ + } + if (destinationPath == null) { + generatePackagesStructure = false; + } else if ("none".equals(destinationPath)) { //$NON-NLS-1$ + destinationPath = null; + } + + if (filenames == null) + throw new InvalidInputException(Main.bind("configure.noSource")); //$NON-NLS-1$ + + // check and set compliance/source/target compatibilities + if (!didSpecifyCompliance){ + if (options.get(CompilerOptions.OPTION_Source).equals(CompilerOptions.VERSION_1_4)){ + options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_4); + } else { + options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_3); + } + } + String compliance = (String)options.get(CompilerOptions.OPTION_Compliance); + if (CompilerOptions.VERSION_1_4.equals(compliance)){ + + // default 1.4 settings + if (!didSpecifySourceLevel){ + options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_4); + } + if (!didSpecifyTarget){ + options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4); + } + } else if (CompilerOptions.VERSION_1_3.equals(compliance)){ + + // default 1.4 settings + if (!didSpecifySourceLevel){ + options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_3); + } + if (!didSpecifyTarget){ + options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_1); + } + } + // compliance must be 1.4 if source is 1.4 + if (options.get(CompilerOptions.OPTION_Source).equals(CompilerOptions.VERSION_1_4) + && !options.get(CompilerOptions.OPTION_Compliance).equals(CompilerOptions.VERSION_1_4)){ + throw new InvalidInputException(Main.bind("configure.incompatibleComplianceForSource14", (String)options.get(CompilerOptions.OPTION_Compliance))); //$NON-NLS-1$ + } + + // target must be 1.4 if source is 1.4 + if (options.get(CompilerOptions.OPTION_Source).equals(CompilerOptions.VERSION_1_4) + && !options.get(CompilerOptions.OPTION_TargetPlatform).equals(CompilerOptions.VERSION_1_4)){ + throw new InvalidInputException(Main.bind("configure.incompatibleTargetForSource14", (String)options.get(CompilerOptions.OPTION_TargetPlatform))); //$NON-NLS-1$ + } + + // target cannot be 1.4 if compliance is 1.3 + if (options.get(CompilerOptions.OPTION_TargetPlatform).equals(CompilerOptions.VERSION_1_4) + && !options.get(CompilerOptions.OPTION_Compliance).equals(CompilerOptions.VERSION_1_4)){ + throw new InvalidInputException(Main.bind("configure.incompatibleComplianceForTarget14", (String)options.get(CompilerOptions.OPTION_Compliance))); //$NON-NLS-1$ + } + + if (log != null) { + try { + out = new PrintWriter(new FileOutputStream(log, false)); + } catch (IOException e) { + throw new InvalidInputException(Main.bind("configure.cannotOpenLog")); //$NON-NLS-1$ + } + } else { + showProgress = false; + } + + if (repetitions == 0) { + repetitions = 1; + } + } + public Map getOptions() { + return this.options; + } + /* + * Answer the component to which will be handed back compilation results from the compiler + */ + public ICompilerRequestor getBatchRequestor() { + return new ICompilerRequestor() { + int lineDelta = 0; + public void acceptResult(CompilationResult compilationResult) { + if (compilationResult.lineSeparatorPositions != null) { + int unitLineCount = compilationResult.lineSeparatorPositions.length; + lineCount += unitLineCount; + lineDelta += unitLineCount; + if (showProgress + && lineDelta > 2000) { // in -log mode, dump a dot every 2000 lines compiled + System.out.print('.'); + lineDelta = 0; + } + } + if (compilationResult.hasProblems()) { + IProblem[] problems = compilationResult.getProblems(); + int count = problems.length; + int localErrorCount = 0; + for (int i = 0; i < count; i++) { + if (problems[i] != null) { + globalProblemsCount++; + if (localErrorCount == 0) + out.println("----------"); //$NON-NLS-1$ + out.print( + globalProblemsCount + + ". " //$NON-NLS-1$ + + (problems[i].isError() + ? Main.bind("requestor.error") //$NON-NLS-1$ + : Main.bind("requestor.warning"))); //$NON-NLS-1$ + if (problems[i].isError()) { + globalErrorsCount++; + } else { + globalWarningsCount++; + } + out.print(" "); //$NON-NLS-1$ + out.print( + Main.bind("requestor.in", new String(problems[i].getOriginatingFileName()))); //$NON-NLS-1$ + try { + out.println( + ((DefaultProblem) problems[i]).errorReportSource( + compilationResult.compilationUnit)); + out.println(problems[i].getMessage()); + } catch (Exception e) { + out.println( + Main.bind("requestor.notRetrieveErrorMessage", problems[i].toString())); //$NON-NLS-1$ + } + out.println("----------"); //$NON-NLS-1$ + if (problems[i].isError()) + localErrorCount++; + } + }; + // exit? + if (systemExitWhenFinished && !proceedOnError && (localErrorCount > 0)) { + out.flush(); + System.exit(-1); + } + } + outputClassFiles(compilationResult); + } + }; + } + /* + * Build the set of compilation source units + */ + public CompilationUnit[] getCompilationUnits() + throws InvalidInputException { + int fileCount = filenames.length; + CompilationUnit[] units = new CompilationUnit[fileCount]; + HashtableOfObject knownFileNames = new HashtableOfObject(fileCount); + + String defaultEncoding = (String) options.get(CompilerOptions.OPTION_Encoding); + if ("".equals(defaultEncoding)) //$NON-NLS-1$ + defaultEncoding = null; //$NON-NLS-1$ + + for (int i = 0; i < fileCount; i++) { + char[] charName = filenames[i].toCharArray(); + if (knownFileNames.get(charName) != null) { + throw new InvalidInputException(Main.bind("unit.more", filenames[i])); //$NON-NLS-1$ + } else { + knownFileNames.put(charName, charName); + } + File file = new File(filenames[i]); + if (!file.exists()) + throw new InvalidInputException(Main.bind("unit.missing", filenames[i])); //$NON-NLS-1$ + String encoding = encodings[i]; + if (encoding == null) + encoding = defaultEncoding; + units[i] = new CompilationUnit(null, filenames[i], encoding); + } + return units; + } + /* + * Low-level API performing the actual compilation + */ + public IErrorHandlingPolicy getHandlingPolicy() { + + // passes the initial set of files to the batch oracle (to avoid finding more than once the same units when case insensitive match) + return new IErrorHandlingPolicy() { + public boolean stopOnFirstError() { + return false; + } + public boolean proceedOnErrors() { + return proceedOnError; // stop if there are some errors + } + }; + } + /* + * Low-level API performing the actual compilation + */ + public FileSystem getLibraryAccess() { + + String defaultEncoding = (String) options.get(CompilerOptions.OPTION_Encoding); + if ("".equals(defaultEncoding)) //$NON-NLS-1$ + defaultEncoding = null; //$NON-NLS-1$ + return new FileSystem(classpaths, filenames, defaultEncoding); + } + /* + * Low-level API performing the actual compilation + */ + public IProblemFactory getProblemFactory() { + return new DefaultProblemFactory(Locale.getDefault()); + } + /* + * External API + */ + + public static void main(String[] argv) { + new Main(new PrintWriter(System.out), true).compile(argv); + } + // Dump classfiles onto disk for all compilation units that where successfull. + + public void outputClassFiles(CompilationResult unitResult) { + + if (!((unitResult == null) || (unitResult.hasErrors() && !proceedOnError))) { + Enumeration classFiles = unitResult.compiledTypes.elements(); + if (!this.generatePackagesStructure) { + while (classFiles.hasMoreElements()) { + this.destinationPath = extractDestinationPathFromSourceFile(unitResult); + // retrieve the key and the corresponding classfile + ClassFile classFile = (ClassFile) classFiles.nextElement(); + char[] filename = classFile.fileName(); + int length = filename.length; + char[] relativeName = new char[length + 6]; + System.arraycopy(filename, 0, relativeName, 0, length); + System.arraycopy(CLASS_FILE_EXTENSION, 0, relativeName, length, 6); + CharOperation.replace(relativeName, '/', File.separatorChar); + try { + ClassFile.writeToDisk( + generatePackagesStructure, + destinationPath, + new String(relativeName), + classFile.getBytes()); + } catch (IOException e) { + String fileName = destinationPath + new String(relativeName); + e.printStackTrace(); + System.out.println(Main.bind("output.noClassFileCreated", fileName)); //$NON-NLS-1$ + } + exportedClassFilesCounter++; + } + } else if (destinationPath != null) { + while (classFiles.hasMoreElements()) { + // retrieve the key and the corresponding classfile + ClassFile classFile = (ClassFile) classFiles.nextElement(); + char[] filename = classFile.fileName(); + int length = filename.length; + char[] relativeName = new char[length + 6]; + System.arraycopy(filename, 0, relativeName, 0, length); + System.arraycopy(CLASS_FILE_EXTENSION, 0, relativeName, length, 6); + CharOperation.replace(relativeName, '/', File.separatorChar); + try { + ClassFile.writeToDisk( + generatePackagesStructure, + destinationPath, + new String(relativeName), + classFile.getBytes()); + } catch (IOException e) { + String fileName = destinationPath + new String(relativeName); + e.printStackTrace(); + System.out.println(Main.bind("output.noClassFileCreated", fileName)); //$NON-NLS-1$ + } + exportedClassFilesCounter++; + } + } + } + } + /* + * Low-level API performing the actual compilation + */ + public void performCompilation() throws InvalidInputException { + + INameEnvironment environment = getLibraryAccess(); + Compiler batchCompiler = + new Compiler( + environment, + getHandlingPolicy(), + getOptions(), + getBatchRequestor(), + getProblemFactory()); + CompilerOptions options = batchCompiler.options; + + // set the non-externally configurable options. + options.setVerboseMode(verbose); + options.produceReferenceInfo(produceRefInfo); + batchCompiler.compile(getCompilationUnits()); + + // cleanup + environment.cleanup(); + } + public void printUsage() { + out.println(Main.bind("misc.usage", Main.bind("compiler.version"))); //$NON-NLS-1$ //$NON-NLS-2$ + out.flush(); + } + + /** + * Creates a NLS catalog for the given locale. + */ + public static void relocalize() { + bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault()); + } + + /** + * Lookup the message with the given ID in this catalog + */ + public static String bind(String id) { + return bind(id, (String[]) null); + } + + /** + * Lookup the message with the given ID in this catalog and bind its + * substitution locations with the given string values. + */ + public static String bind(String id, String[] bindings) { + if (id == null) + return "No message available"; //$NON-NLS-1$ + String message = null; + try { + message = bundle.getString(id); + } catch (MissingResourceException e) { + // If we got an exception looking for the message, fail gracefully by just returning + // the id we were looking for. In most cases this is semi-informative so is not too bad. + return "Missing message: " + id + " in: " + bundleName; //$NON-NLS-2$ //$NON-NLS-1$ + } + // for compatibility with MessageFormat which eliminates double quotes in original message + char[] messageWithNoDoubleQuotes = + CharOperation.replace(message.toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE); + message = new String(messageWithNoDoubleQuotes); + + if (bindings == null) + return message; + + int length = message.length(); + int start = -1; + int end = length; + StringBuffer output = new StringBuffer(80); + while (true) { + if ((end = message.indexOf('{', start)) > -1) { + output.append(message.substring(start + 1, end)); + if ((start = message.indexOf('}', end)) > -1) { + int index = -1; + try { + index = Integer.parseInt(message.substring(end + 1, start)); + output.append(bindings[index]); + } catch (NumberFormatException nfe) { + output.append(message.substring(end + 1, start + 1)); + } catch (ArrayIndexOutOfBoundsException e) { + output.append("{missing " + Integer.toString(index) + "}"); //$NON-NLS-2$ //$NON-NLS-1$ + } + } else { + output.append(message.substring(end, length)); + break; + } + } else { + output.append(message.substring(start + 1, length)); + break; + } + } + return output.toString(); + } + + /** + * Lookup the message with the given ID in this catalog and bind its + * substitution locations with the given string. + */ + public static String bind(String id, String binding) { + return bind(id, new String[] { binding }); + } + + /** + * Lookup the message with the given ID in this catalog and bind its + * substitution locations with the given strings. + */ + public static String bind(String id, String binding1, String binding2) { + return bind(id, new String[] { binding1, binding2 }); + } + + public String extractDestinationPathFromSourceFile(CompilationResult result) { + ICompilationUnit compilationUnit = result.compilationUnit; + if (compilationUnit != null) { + char[] fileName = compilationUnit.getFileName(); + int lastIndex = CharOperation.lastIndexOf(java.io.File.separatorChar, fileName); + if (lastIndex == -1) { + return System.getProperty("user.dir"); //$NON-NLS-1$ + } + return new String(CharOperation.subarray(fileName, 0, lastIndex)); + } + return System.getProperty("user.dir"); //$NON-NLS-1$ + } + +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/ClassFileConstants.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/ClassFileConstants.java new file mode 100644 index 0000000..364856e --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/ClassFileConstants.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.classfmt; + +import net.sourceforge.phpdt.internal.compiler.env.*; + +public interface ClassFileConstants extends IConstants { + + int Utf8Tag = 1; + int IntegerTag = 3; + int FloatTag = 4; + int LongTag = 5; + int DoubleTag = 6; + int ClassTag = 7; + int StringTag = 8; + int FieldRefTag = 9; + int MethodRefTag = 10; + int InterfaceMethodRefTag = 11; + int NameAndTypeTag = 12; + + int ConstantMethodRefFixedSize = 5; + int ConstantClassFixedSize = 3; + int ConstantDoubleFixedSize = 9; + int ConstantFieldRefFixedSize = 5; + int ConstantFloatFixedSize = 5; + int ConstantIntegerFixedSize = 5; + int ConstantInterfaceMethodRefFixedSize = 5; + int ConstantLongFixedSize = 9; + int ConstantStringFixedSize = 3; + int ConstantUtf8FixedSize = 3; + int ConstantNameAndTypeFixedSize = 5; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/ClassFileReader.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/ClassFileReader.java new file mode 100644 index 0000000..ae23f4b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/ClassFileReader.java @@ -0,0 +1,788 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.classfmt; + +import net.sourceforge.phpdt.internal.compiler.codegen.*; +import net.sourceforge.phpdt.internal.compiler.env.*; +import net.sourceforge.phpdt.internal.compiler.impl.Constant; +import net.sourceforge.phpdt.internal.compiler.impl.NullConstant; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeIds; +import net.sourceforge.phpdt.internal.compiler.util.*; + +import java.io.*; +import java.util.Arrays; + +public class ClassFileReader extends ClassFileStruct implements AttributeNamesConstants, IBinaryType { + private int constantPoolCount; + private int[] constantPoolOffsets; + private int accessFlags; + private char[] className; + private char[] superclassName; + private int interfacesCount; + private char[][] interfaceNames; + private int fieldsCount; + private FieldInfo[] fields; + private int methodsCount; + private MethodInfo[] methods; + private InnerClassInfo[] innerInfos; + private char[] sourceFileName; + // initialized in case the .class file is a nested type + private InnerClassInfo innerInfo; + private char[] classFileName; + private int classNameIndex; + private int innerInfoIndex; +/** + * @param classFileBytes byte[] + * Actual bytes of a .class file + * + * @param fileName char[] + * Actual name of the file that contains the bytes, can be null + * + * @param fullyInitialize boolean + * Flag to fully initialize the new object + * @exception ClassFormatException + */ +public ClassFileReader(byte[] classFileBytes, char[] fileName, boolean fullyInitialize) throws ClassFormatException { + // This method looks ugly but is actually quite simple, the constantPool is constructed + // in 3 passes. All non-primitive constant pool members that usually refer to other members + // by index are tweaked to have their value in inst vars, this minor cost at read-time makes + // all subsequent uses of the constant pool element faster. + super(classFileBytes, 0); + this.classFileName = fileName; + int readOffset = 10; + try { + constantPoolCount = this.u2At(8); + // Pass #1 - Fill in all primitive constants + this.constantPoolOffsets = new int[constantPoolCount]; + for (int i = 1; i < constantPoolCount; i++) { + int tag = this.u1At(readOffset); + switch (tag) { + case Utf8Tag : + this.constantPoolOffsets[i] = readOffset; + readOffset += u2At(readOffset + 1); + readOffset += ConstantUtf8FixedSize; + break; + case IntegerTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantIntegerFixedSize; + break; + case FloatTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantFloatFixedSize; + break; + case LongTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantLongFixedSize; + i++; + break; + case DoubleTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantDoubleFixedSize; + i++; + break; + case ClassTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantClassFixedSize; + break; + case StringTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantStringFixedSize; + break; + case FieldRefTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantFieldRefFixedSize; + break; + case MethodRefTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantMethodRefFixedSize; + break; + case InterfaceMethodRefTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantInterfaceMethodRefFixedSize; + break; + case NameAndTypeTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantNameAndTypeFixedSize; + } + } + // Read and validate access flags + this.accessFlags = u2At(readOffset); + readOffset += 2; + + // Read the classname, use exception handlers to catch bad format + this.classNameIndex = u2At(readOffset); + this.className = getConstantClassNameAt(this.classNameIndex); + readOffset += 2; + + // Read the superclass name, can be null for java.lang.Object + int superclassNameIndex = u2At(readOffset); + readOffset += 2; + // if superclassNameIndex is equals to 0 there is no need to set a value for the + // field this.superclassName. null is fine. + if (superclassNameIndex != 0) { + this.superclassName = getConstantClassNameAt(superclassNameIndex); + } + + // Read the interfaces, use exception handlers to catch bad format + this.interfacesCount = u2At(readOffset); + readOffset += 2; + if (this.interfacesCount != 0) { + this.interfaceNames = new char[this.interfacesCount][]; + for (int i = 0; i < this.interfacesCount; i++) { + this.interfaceNames[i] = getConstantClassNameAt(u2At(readOffset)); + readOffset += 2; + } + } + // Read the this.fields, use exception handlers to catch bad format + this.fieldsCount = u2At(readOffset); + readOffset += 2; + if (this.fieldsCount != 0) { + FieldInfo field; + this.fields = new FieldInfo[this.fieldsCount]; + for (int i = 0; i < this.fieldsCount; i++) { + field = new FieldInfo(reference, this.constantPoolOffsets, readOffset); + this.fields[i] = field; + readOffset += field.sizeInBytes(); + } + } + // Read the this.methods + this.methodsCount = u2At(readOffset); + readOffset += 2; + if (this.methodsCount != 0) { + this.methods = new MethodInfo[this.methodsCount]; + MethodInfo method; + for (int i = 0; i < this.methodsCount; i++) { + method = new MethodInfo(reference, this.constantPoolOffsets, readOffset); + this.methods[i] = method; + readOffset += method.sizeInBytes(); + } + } + + // Read the attributes + int attributesCount = u2At(readOffset); + readOffset += 2; + + for (int i = 0; i < attributesCount; i++) { + int utf8Offset = this.constantPoolOffsets[u2At(readOffset)]; + char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + if (CharOperation.equals(attributeName, DeprecatedName)) { + this.accessFlags |= AccDeprecated; + } else { + if (CharOperation.equals(attributeName, InnerClassName)) { + int innerOffset = readOffset + 6; + int number_of_classes = u2At(innerOffset); + if (number_of_classes != 0) { + this.innerInfos = new InnerClassInfo[number_of_classes]; + for (int j = 0; j < number_of_classes; j++) { + this.innerInfos[j] = + new InnerClassInfo(reference, this.constantPoolOffsets, innerOffset + 2); + if (this.classNameIndex == this.innerInfos[j].innerClassNameIndex) { + this.innerInfo = this.innerInfos[j]; + this.innerInfoIndex = j; + } + innerOffset += 8; + } + } + } else { + if (CharOperation.equals(attributeName, SourceName)) { + utf8Offset = this.constantPoolOffsets[u2At(readOffset + 6)]; + this.sourceFileName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + } else { + if (CharOperation.equals(attributeName, SyntheticName)) { + this.accessFlags |= AccSynthetic; + } + } + } + } + readOffset += (6 + u4At(readOffset + 2)); + } + if (fullyInitialize) { + this.initialize(); + } + } catch (Exception e) { + throw new ClassFormatException( + ClassFormatException.ErrTruncatedInput, + readOffset); + } +} + +/** + * @param classFileBytes Actual bytes of a .class file + * @param fileName Actual name of the file that contains the bytes, can be null + * + * @exception ClassFormatException + */ +public ClassFileReader(byte classFileBytes[], char[] fileName) throws ClassFormatException { + this(classFileBytes, fileName, false); +} + +/** + * Answer the receiver's access flags. The value of the access_flags + * item is a mask of modifiers used with class and interface declarations. + * @return int + */ +public int accessFlags() { + return this.accessFlags; +} +/** + * Answer the char array that corresponds to the class name of the constant class. + * constantPoolIndex is the index in the constant pool that is a constant class entry. + * + * @param int constantPoolIndex + * @return char[] + */ +private char[] getConstantClassNameAt(int constantPoolIndex) { + int utf8Offset = this.constantPoolOffsets[u2At(this.constantPoolOffsets[constantPoolIndex] + 1)]; + return utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); +} +/** + * Answer the int array that corresponds to all the offsets of each entry in the constant pool + * + * @return int[] + */ +public int[] getConstantPoolOffsets() { + return this.constantPoolOffsets; +} +/* + * Answer the resolved compoundName of the enclosing type + * or null if the receiver is a top level type. + */ +public char[] getEnclosingTypeName() { + if (this.innerInfo != null && !this.isAnonymous()) { + return this.innerInfo.getEnclosingTypeName(); + } + return null; +} +/** + * Answer the receiver's this.fields or null if the array is empty. + * @return org.eclipse.jdt.internal.compiler.api.IBinaryField[] + */ +public IBinaryField[] getFields() { + return this.fields; +} +/** + * Answer the file name which defines the type. + * The format is unspecified. + */ +public char[] getFileName() { + return this.classFileName; +} +/** + * Answer the source name if the receiver is a inner type. Return null if it is an anonymous class or if the receiver is a top-level class. + * e.g. + * public class A { + * public class B { + * } + * public void foo() { + * class C {} + * } + * public Runnable bar() { + * return new Runnable() { + * public void run() {} + * }; + * } + * } + * It returns {'B'} for the member A$B + * It returns null for A + * It returns {'C'} for the local class A$1$C + * It returns null for the anonymous A$1 + * @return char[] + */ +public char[] getInnerSourceName() { + if (this.innerInfo != null) + return this.innerInfo.getSourceName(); + return null; +} +/** + * Answer the resolved names of the receiver's interfaces in the + * class file format as specified in section 4.2 of the Java 2 VM spec + * or null if the array is empty. + * + * For example, java.lang.String is java/lang/String. + * @return char[][] + */ +public char[][] getInterfaceNames() { + return this.interfaceNames; +} +/** + * Answer the receiver's nested types or null if the array is empty. + * + * This nested type info is extracted from the inner class attributes. + * Ask the name environment to find a member type using its compound name + * @return org.eclipse.jdt.internal.compiler.api.IBinaryNestedType[] + */ +public IBinaryNestedType[] getMemberTypes() { + // we might have some member types of the current type + if (this.innerInfos == null) return null; + + int length = this.innerInfos.length; + int startingIndex = this.innerInfo != null ? this.innerInfoIndex + 1 : 0; + if (length != startingIndex) { + IBinaryNestedType[] memberTypes = + new IBinaryNestedType[length - this.innerInfoIndex]; + int memberTypeIndex = 0; + for (int i = startingIndex; i < length; i++) { + InnerClassInfo currentInnerInfo = this.innerInfos[i]; + int outerClassNameIdx = currentInnerInfo.outerClassNameIndex; + int innerNameIndex = currentInnerInfo.innerNameIndex; + /* + * Checking that outerClassNameIDx is different from 0 should be enough to determine if an inner class + * attribute entry is a member class, but due to the bug: + * http://dev.eclipse.org/bugs/show_bug.cgi?id=14592 + * we needed to add an extra check. So we check that innerNameIndex is different from 0 as well. + */ + if (outerClassNameIdx != 0 && innerNameIndex != 0 && outerClassNameIdx == this.classNameIndex) { + memberTypes[memberTypeIndex++] = currentInnerInfo; + } + } + if (memberTypeIndex == 0) return null; + if (memberTypeIndex != memberTypes.length) { + // we need to resize the memberTypes array. Some local or anonymous classes + // are present in the current class. + System.arraycopy( + memberTypes, + 0, + (memberTypes = new IBinaryNestedType[memberTypeIndex]), + 0, + memberTypeIndex); + } + return memberTypes; + } + return null; +} +/** + * Answer the receiver's this.methods or null if the array is empty. + * @return org.eclipse.jdt.internal.compiler.api.env.IBinaryMethod[] + */ +public IBinaryMethod[] getMethods() { + return this.methods; +} +/** + * Answer an int whose bits are set according the access constants + * defined by the VM spec. + * Set the AccDeprecated and AccSynthetic bits if necessary + * @return int + */ +public int getModifiers() { + if (this.innerInfo != null) { + return this.innerInfo.getModifiers(); + } + return this.accessFlags; +} +/** + * Answer the resolved name of the type in the + * class file format as specified in section 4.2 of the Java 2 VM spec. + * + * For example, java.lang.String is java/lang/String. + * @return char[] + */ +public char[] getName() { + return this.className; +} +/** + * Answer the resolved name of the receiver's superclass in the + * class file format as specified in section 4.2 of the Java 2 VM spec + * or null if it does not have one. + * + * For example, java.lang.String is java/lang/String. + * @return char[] + */ +public char[] getSuperclassName() { + return this.superclassName; +} +/** + * Answer true if the receiver is an anonymous type, false otherwise + * + * @return boolean + */ +public boolean isAnonymous() { + if (this.innerInfo == null) return false; + char[] sourceName = this.innerInfo.getSourceName(); + return (sourceName == null || sourceName.length == 0); +} +/** + * Answer whether the receiver contains the resolved binary form + * or the unresolved source form of the type. + * @return boolean + */ +public boolean isBinaryType() { + return true; +} +/** + * Answer true if the receiver is a class. False otherwise. + * @return boolean + */ +public boolean isClass() { + return (getModifiers() & AccInterface) == 0; +} +/** + * Answer true if the receiver is an interface. False otherwise. + * @return boolean + */ +public boolean isInterface() { + return (getModifiers() & AccInterface) != 0; +} +/** + * Answer true if the receiver is a local type, false otherwise + * + * @return boolean + */ +public boolean isLocal() { + return + this.innerInfo != null + && this.innerInfo.getEnclosingTypeName() == null + && this.innerInfo.getSourceName() != null; +} +/** + * Answer true if the receiver is a member type, false otherwise + * + * @return boolean + */ +public boolean isMember() { + return this.innerInfo != null && this.innerInfo.getEnclosingTypeName() != null; +} +/** + * Answer true if the receiver is a nested type, false otherwise + * + * @return boolean + */ +public boolean isNestedType() { + return this.innerInfo != null; +} +public static ClassFileReader read(File file) throws ClassFormatException, IOException { + return read(file, false); +} +public static ClassFileReader read(File file, boolean fullyInitialize) throws ClassFormatException, IOException { + byte classFileBytes[] = Util.getFileByteContent(file); + ClassFileReader classFileReader = new ClassFileReader(classFileBytes, file.getAbsolutePath().toCharArray()); + if (fullyInitialize) { + classFileReader.initialize(); + } + return classFileReader; +} +public static ClassFileReader read(String fileName) throws ClassFormatException, java.io.IOException { + return read(fileName, false); +} +public static ClassFileReader read(String fileName, boolean fullyInitialize) throws ClassFormatException, java.io.IOException { + return read(new File(fileName), fullyInitialize); +} +public static ClassFileReader read( + java.util.zip.ZipFile zip, + String filename) + throws ClassFormatException, java.io.IOException { + return read(zip, filename, false); +} +public static ClassFileReader read( + java.util.zip.ZipFile zip, + String filename, + boolean fullyInitialize) + throws ClassFormatException, java.io.IOException { + java.util.zip.ZipEntry ze = zip.getEntry(filename); + if (ze == null) + return null; + byte classFileBytes[] = Util.getZipEntryByteContent(ze, zip); + ClassFileReader classFileReader = new ClassFileReader(classFileBytes, filename.toCharArray()); + if (fullyInitialize) { + classFileReader.initialize(); + } + return classFileReader; +} + +/** + * Answer the source file name attribute. Return null if there is no source file attribute for the receiver. + * + * @return char[] + */ +public char[] sourceFileName() { + return this.sourceFileName; +} +public String toString() { + java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream(); + java.io.PrintWriter print = new java.io.PrintWriter(out); + + print.println(this.getClass().getName() + "{"); //$NON-NLS-1$ + print.println(" this.className: " + new String(getName())); //$NON-NLS-1$ + print.println(" this.superclassName: " + (getSuperclassName() == null ? "null" : new String(getSuperclassName()))); //$NON-NLS-2$ //$NON-NLS-1$ + print.println(" access_flags: " + ClassFileStruct.printTypeModifiers(this.accessFlags()) + "(" + this.accessFlags() + ")"); //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-2$ + + print.flush(); + return out.toString(); +} +/** + * Check if the receiver has structural changes compare to the byte array in argument. + * Structural changes are: + * - modifiers changes for the class, the this.fields or the this.methods + * - signature changes for this.fields or this.methods. + * - changes in the number of this.fields or this.methods + * - changes for field constants + * - changes for thrown exceptions + * - change for the super class or any super interfaces. + * - changes for member types name or modifiers + * If any of these changes occurs, the method returns true. false otherwise. + * The synthetic fields are included and the members are not required to be sorted. + * @param newBytes the bytes of the .class file we want to compare the receiver to + * @return boolean Returns true is there is a structural change between the two .class files, false otherwise + */ +public boolean hasStructuralChanges(byte[] newBytes) { + return hasStructuralChanges(newBytes, true, true); +} +/** + * Check if the receiver has structural changes compare to the byte array in argument. + * Structural changes are: + * - modifiers changes for the class, the this.fields or the this.methods + * - signature changes for this.fields or this.methods. + * - changes in the number of this.fields or this.methods + * - changes for field constants + * - changes for thrown exceptions + * - change for the super class or any super interfaces. + * - changes for member types name or modifiers + * If any of these changes occurs, the method returns true. false otherwise. + * @param newBytes the bytes of the .class file we want to compare the receiver to + * @param orderRequired a boolean indicating whether the members should be sorted or not + * @param excludesSynthetics a boolean indicating whether the synthetic members should be used in the comparison + * @return boolean Returns true is there is a structural change between the two .class files, false otherwise + */ +public boolean hasStructuralChanges(byte[] newBytes, boolean orderRequired, boolean excludesSynthetic) { + try { + ClassFileReader newClassFile = + new ClassFileReader(newBytes, this.classFileName); + // type level comparison + // modifiers + if (this.getModifiers() != newClassFile.getModifiers()) + return true; + // superclass + if (!CharOperation.equals(this.getSuperclassName(), newClassFile.getSuperclassName())) + return true; + // interfaces + char[][] newInterfacesNames = newClassFile.getInterfaceNames(); + if (this.interfaceNames != newInterfacesNames) { // TypeConstants.NoSuperInterfaces + int newInterfacesLength = newInterfacesNames == null ? 0 : newInterfacesNames.length; + if (newInterfacesLength != this.interfacesCount) + return true; + for (int i = 0, max = this.interfacesCount; i < max; i++) + if (!CharOperation.equals(this.interfaceNames[i], newInterfacesNames[i])) + return true; + } + + // member types + IBinaryNestedType[] currentMemberTypes = (IBinaryNestedType[]) this.getMemberTypes(); + IBinaryNestedType[] otherMemberTypes = (IBinaryNestedType[]) newClassFile.getMemberTypes(); + if (currentMemberTypes != otherMemberTypes) { // TypeConstants.NoMemberTypes + int currentMemberTypeLength = currentMemberTypes == null ? 0 : currentMemberTypes.length; + int otherMemberTypeLength = otherMemberTypes == null ? 0 : otherMemberTypes.length; + if (currentMemberTypeLength != otherMemberTypeLength) + return true; + for (int i = 0; i < currentMemberTypeLength; i++) + if (!CharOperation.equals(currentMemberTypes[i].getName(), otherMemberTypes[i].getName()) + || currentMemberTypes[i].getModifiers() != otherMemberTypes[i].getModifiers()) + return true; + } + + // fields + FieldInfo[] otherFieldInfos = (FieldInfo[]) newClassFile.getFields(); + int otherFieldInfosLength = otherFieldInfos == null ? 0 : otherFieldInfos.length; + boolean compareFields = true; + if (this.fieldsCount == otherFieldInfosLength) { + int i = 0; + for (; i < this.fieldsCount; i++) + if (hasStructuralFieldChanges(this.fields[i], otherFieldInfos[i])) break; + if ((compareFields = i != this.fieldsCount) && !orderRequired && !excludesSynthetic) + return true; + } + if (compareFields) { + if (this.fieldsCount != otherFieldInfosLength && !excludesSynthetic) + return true; + if (orderRequired) { + if (this.fieldsCount != 0) + Arrays.sort(this.fields); + if (otherFieldInfosLength != 0) + Arrays.sort(otherFieldInfos); + } + if (excludesSynthetic) { + if (hasNonSyntheticFieldChanges(this.fields, otherFieldInfos)) + return true; + } else { + for (int i = 0; i < this.fieldsCount; i++) + if (hasStructuralFieldChanges(this.fields[i], otherFieldInfos[i])) + return true; + } + } + + // methods + MethodInfo[] otherMethodInfos = (MethodInfo[]) newClassFile.getMethods(); + int otherMethodInfosLength = otherMethodInfos == null ? 0 : otherMethodInfos.length; + boolean compareMethods = true; + if (this.methodsCount == otherMethodInfosLength) { + int i = 0; + for (; i < this.methodsCount; i++) + if (hasStructuralMethodChanges(this.methods[i], otherMethodInfos[i])) break; + if ((compareMethods = i != this.methodsCount) && !orderRequired && !excludesSynthetic) + return true; + } + if (compareMethods) { + if (this.methodsCount != otherMethodInfosLength && !excludesSynthetic) + return true; + if (orderRequired) { + if (this.methodsCount != 0) + Arrays.sort(this.methods); + if (otherMethodInfosLength != 0) + Arrays.sort(otherMethodInfos); + } + if (excludesSynthetic) { + if (hasNonSyntheticMethodChanges(this.methods, otherMethodInfos)) + return true; + } else { + for (int i = 0; i < this.methodsCount; i++) + if (hasStructuralMethodChanges(this.methods[i], otherMethodInfos[i])) + return true; + } + } + + return false; + } catch (ClassFormatException e) { + return true; + } +} +private boolean hasNonSyntheticFieldChanges(FieldInfo[] currentFieldInfos, FieldInfo[] otherFieldInfos) { + int length1 = currentFieldInfos == null ? 0 : currentFieldInfos.length; + int length2 = otherFieldInfos == null ? 0 : otherFieldInfos.length; + int index1 = 0; + int index2 = 0; + + end : while (index1 < length1 && index2 < length2) { + while (currentFieldInfos[index1].isSynthetic()) { + if (++index1 >= length1) break end; + } + while (otherFieldInfos[index2].isSynthetic()) { + if (++index2 >= length2) break end; + } + if (hasStructuralFieldChanges(currentFieldInfos[index1++], otherFieldInfos[index2++])) + return true; + } + + while (index1 < length1) { + if (!currentFieldInfos[index1++].isSynthetic()) return true; + } + while (index2 < length2) { + if (!otherFieldInfos[index2++].isSynthetic()) return true; + } + return false; +} +private boolean hasStructuralFieldChanges(FieldInfo currentFieldInfo, FieldInfo otherFieldInfo) { + if (currentFieldInfo.getModifiers() != otherFieldInfo.getModifiers()) + return true; + if (!CharOperation.equals(currentFieldInfo.getName(), otherFieldInfo.getName())) + return true; + if (!CharOperation.equals(currentFieldInfo.getTypeName(), otherFieldInfo.getTypeName())) + return true; + if (currentFieldInfo.hasConstant() != otherFieldInfo.hasConstant()) + return true; + if (currentFieldInfo.hasConstant()) { + Constant currentConstant = currentFieldInfo.getConstant(); + Constant otherConstant = otherFieldInfo.getConstant(); + if (currentConstant.typeID() != otherConstant.typeID()) + return true; + if (!currentConstant.getClass().equals(otherConstant.getClass())) + return true; + switch (currentConstant.typeID()) { + case TypeIds.T_int : + return currentConstant.intValue() != otherConstant.intValue(); + case TypeIds.T_byte : + return currentConstant.byteValue() != otherConstant.byteValue(); + case TypeIds.T_short : + return currentConstant.shortValue() != otherConstant.shortValue(); + case TypeIds.T_char : + return currentConstant.charValue() != otherConstant.charValue(); + case TypeIds.T_float : + return currentConstant.floatValue() != otherConstant.floatValue(); + case TypeIds.T_double : + return currentConstant.doubleValue() != otherConstant.doubleValue(); + case TypeIds.T_boolean : + return currentConstant.booleanValue() != otherConstant.booleanValue(); + case TypeIds.T_String : + return !currentConstant.stringValue().equals(otherConstant.stringValue()); + case TypeIds.T_null : + return otherConstant != NullConstant.Default; + } + } + return false; +} +private boolean hasNonSyntheticMethodChanges(MethodInfo[] currentMethodInfos, MethodInfo[] otherMethodInfos) { + int length1 = currentMethodInfos == null ? 0 : currentMethodInfos.length; + int length2 = otherMethodInfos == null ? 0 : otherMethodInfos.length; + int index1 = 0; + int index2 = 0; + + MethodInfo m; + end : while (index1 < length1 && index2 < length2) { + while ((m = currentMethodInfos[index1]).isSynthetic() || m.isClinit()) { + if (++index1 >= length1) break end; + } + while ((m = otherMethodInfos[index2]).isSynthetic() || m.isClinit()) { + if (++index2 >= length2) break end; + } + if (hasStructuralMethodChanges(currentMethodInfos[index1++], otherMethodInfos[index2++])) + return true; + } + + while (index1 < length1) { + if (!((m = currentMethodInfos[index1++]).isSynthetic() || m.isClinit())) return true; + } + while (index2 < length2) { + if (!((m = otherMethodInfos[index2++]).isSynthetic() || m.isClinit())) return true; + } + return false; +} +private boolean hasStructuralMethodChanges(MethodInfo currentMethodInfo, MethodInfo otherMethodInfo) { + if (currentMethodInfo.getModifiers() != otherMethodInfo.getModifiers()) + return true; + if (!CharOperation.equals(currentMethodInfo.getSelector(), otherMethodInfo.getSelector())) + return true; + if (!CharOperation.equals(currentMethodInfo.getMethodDescriptor(), otherMethodInfo.getMethodDescriptor())) + return true; + + char[][] currentThrownExceptions = currentMethodInfo.getExceptionTypeNames(); + char[][] otherThrownExceptions = otherMethodInfo.getExceptionTypeNames(); + if (currentThrownExceptions != otherThrownExceptions) { // TypeConstants.NoExceptions + int currentThrownExceptionsLength = currentThrownExceptions == null ? 0 : currentThrownExceptions.length; + int otherThrownExceptionsLength = otherThrownExceptions == null ? 0 : otherThrownExceptions.length; + if (currentThrownExceptionsLength != otherThrownExceptionsLength) + return true; + for (int k = 0; k < currentThrownExceptionsLength; k++) + if (!CharOperation.equals(currentThrownExceptions[k], otherThrownExceptions[k])) + return true; + } + return false; +} +/** + * This method is used to fully initialize the contents of the receiver. All methodinfos, fields infos + * will be therefore fully initialized and we can get rid of the bytes. + */ +private void initialize() { + for (int i = 0, max = fieldsCount; i < max; i++) { + fields[i].initialize(); + } + for (int i = 0, max = methodsCount; i < max; i++) { + methods[i].initialize(); + } + if (innerInfos != null) { + for (int i = 0, max = innerInfos.length; i < max; i++) { + innerInfos[i].initialize(); + } + } + this.reset(); +} +protected void reset() { + this.constantPoolOffsets = null; + super.reset(); +} + +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/ClassFileStruct.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/ClassFileStruct.java new file mode 100644 index 0000000..1f62a71 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/ClassFileStruct.java @@ -0,0 +1,184 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.classfmt; + +abstract public class ClassFileStruct implements ClassFileConstants { + byte[] reference; + int structOffset; +public ClassFileStruct(byte classFileBytes[], int off) { + reference = classFileBytes; + structOffset = off; +} +public ClassFileStruct (byte classFileBytes[], int off, boolean verifyStructure) { + reference = classFileBytes; + structOffset = off; +} +public double doubleAt(int relativeOffset) { + return (Double.longBitsToDouble(this.i8At(relativeOffset))); +} +public float floatAt(int relativeOffset) { + return (Float.intBitsToFloat(this.i4At(relativeOffset))); +} +public int i1At(int relativeOffset) { + return reference[relativeOffset + structOffset]; +} +public int i2At(int relativeOffset) { + int position = relativeOffset + structOffset; + return (reference[position++] << 8) + (reference[position] & 0xFF); +} +public int i4At(int relativeOffset) { + int position = relativeOffset + structOffset; + return ((reference[position++] & 0xFF) << 24) + ((reference[position++] & 0xFF) << 16) + ((reference[position++] & 0xFF) << 8) + (reference[position] & 0xFF); +} +public long i8At(int relativeOffset) { + int position = relativeOffset + structOffset; + return (((long) (reference[position++] & 0xFF)) << 56) + (((long) (reference[position++] & 0xFF)) << 48) + (((long) (reference[position++] & 0xFF)) << 40) + (((long) (reference[position++] & 0xFF)) << 32) + (((long) (reference[position++] & 0xFF)) << 24) + (((long) (reference[position++] & 0xFF)) << 16) + (((long) (reference[position++] & 0xFF)) << 8) + ((long) (reference[position++] & 0xFF)); +} +public static String printTypeModifiers(int modifiers) { + + java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream(); + java.io.PrintWriter print = new java.io.PrintWriter(out); + + if ((modifiers & AccPublic) != 0) print.print("public "); //$NON-NLS-1$ + if ((modifiers & AccPrivate) != 0) print.print("private "); //$NON-NLS-1$ + if ((modifiers & AccFinal) != 0) print.print("final "); //$NON-NLS-1$ + if ((modifiers & AccSuper) != 0) print.print("super "); //$NON-NLS-1$ + if ((modifiers & AccInterface) != 0) print.print("interface "); //$NON-NLS-1$ + if ((modifiers & AccAbstract) != 0) print.print("abstract "); //$NON-NLS-1$ + print.flush(); + return out.toString(); +} +public int u1At(int relativeOffset) { + return (reference[relativeOffset + structOffset] & 0xFF); +} +public int u2At(int relativeOffset) { + int position = relativeOffset + structOffset; + return ((reference[position++] & 0xFF) << 8) + (reference[position] & 0xFF); +} +public long u4At(int relativeOffset) { + int position = relativeOffset + structOffset; + return (((reference[position++] & 0xFFL) << 24) + ((reference[position++] & 0xFF) << 16) + ((reference[position++] & 0xFF) << 8) + (reference[position] & 0xFF)); +} +public char[] utf8At(int relativeOffset, int bytesAvailable) { + int x, y, z; + int length = bytesAvailable; + char outputBuf[] = new char[bytesAvailable]; + int outputPos = 0; + int readOffset = structOffset + relativeOffset; + + while (length != 0) { + x = reference[readOffset++] & 0xFF; + length--; + if ((0x80 & x) != 0) { + y = this.reference[readOffset++] & 0xFF; + length--; + if ((x & 0x20) != 0) { + z = this.reference[readOffset++] & 0xFF; + length--; + x = ((x & 0x1F) << 12) + ((y & 0x3F) << 6) + (z & 0x3F); + } else { + x = ((x & 0x1F) << 6) + (y & 0x3F); + } + } + outputBuf[outputPos++] = (char) x; + } + + if (outputPos != bytesAvailable) { + System.arraycopy(outputBuf, 0, (outputBuf = new char[outputPos]), 0, outputPos); + } + return outputBuf; +} + +protected void reset() { + this.reference = null; +} + +public char[] utf8At(int relativeOffset, int bytesAvailable, boolean testValidity) throws ClassFormatException { + int x, y, z; + int length = bytesAvailable; + char outputBuf[] = new char[bytesAvailable]; + int outputPos = 0; + int readOffset = structOffset + relativeOffset; + + while (length != 0) { + x = reference[readOffset++] & 0xFF; + length--; + if ((0x80 & x) != 0) { + if (testValidity) { + if ((0x40 & x) == 0) { + throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8); + } + if (length < 1) { + throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8); + } + } + y = this.reference[readOffset++] & 0xFF; + length--; + if (testValidity) { + if ((y & 0xC0) != 0x80) { + throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8); + } + } + if ((x & 0x20) != 0) { + if (testValidity && (length < 1)) { + throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8); + } + z = this.reference[readOffset++] & 0xFF; + length--; + if (testValidity && ((z & 0xC0) != 0x80)) { + throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8); + } + x = ((x & 0x1F) << 12) + ((y & 0x3F) << 6) + (z & 0x3F); + if (testValidity && (x < 0x0800)) { + throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8); + } + } else { + x = ((x & 0x1F) << 6) + (y & 0x3F); + if (testValidity && !((x == 0) || (x >= 0x80))) { + throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8); + } + } + } else { + if (testValidity && x == 0) { + throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8); + } + } + outputBuf[outputPos++] = (char) x; + } + + if (outputPos != bytesAvailable) { + System.arraycopy(outputBuf, 0, (outputBuf = new char[outputPos]), 0, outputPos); + } + return outputBuf; +} +public static void verifyMethodNameAndSignature(char[] name, char[] signature) throws ClassFormatException { + + // ensure name is not empty + if (name.length == 0) { + throw new ClassFormatException(ClassFormatException.ErrInvalidMethodName); + } + + // if name begins with the < character it must be clinit or init + if (name[0] == '<') { + if (new String(name).equals("") || new String(name).equals("")) { //$NON-NLS-2$ //$NON-NLS-1$ + int signatureLength = signature.length; + if (!((signatureLength > 2) + && (signature[0] == '(') + && (signature[signatureLength - 2] == ')') + && (signature[signatureLength - 1] == 'V'))) { + throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature); + } + } else { + throw new ClassFormatException(ClassFormatException.ErrInvalidMethodName); + } + } +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/ClassFormatException.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/ClassFormatException.java new file mode 100644 index 0000000..31ce04d --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/ClassFormatException.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.classfmt; + +public class ClassFormatException extends Exception { + private int errorCode; + private int bufferPosition; + + public static final int ErrBadMagic = 1; + public static final int ErrBadMinorVersion = 2; + public static final int ErrBadMajorVersion = 3; + + public static final int ErrBadConstantClass= 4; + public static final int ErrBadConstantString= 5; + public static final int ErrBadConstantNameAndType = 6; + public static final int ErrBadConstantFieldRef= 7; + public static final int ErrBadConstantMethodRef = 8; + public static final int ErrBadConstantInterfaceMethodRef = 9; + public static final int ErrBadConstantPoolIndex = 10; + public static final int ErrBadSuperclassName = 11; + public static final int ErrInterfaceCannotBeFinal = 12; + public static final int ErrInterfaceMustBeAbstract = 13; + public static final int ErrBadModifiers = 14; + public static final int ErrClassCannotBeAbstractFinal = 15; + public static final int ErrBadClassname = 16; + public static final int ErrBadFieldInfo = 17; + public static final int ErrBadMethodInfo = 17; + + public static final int ErrEmptyConstantPool =18; + public static final int ErrMalformedUtf8 = 19; + public static final int ErrUnknownConstantTag = 20; + public static final int ErrTruncatedInput = 21; + public static final int ErrMethodMustBeAbstract = 22; + public static final int ErrMalformedAttribute = 23; + public static final int ErrBadInterface = 24; + public static final int ErrInterfaceMustSubclassObject = 25; + public static final int ErrIncorrectInterfaceMethods = 26; + public static final int ErrInvalidMethodName = 27; + public static final int ErrInvalidMethodSignature = 28; + +public ClassFormatException(int code) { + errorCode = code; +} +public ClassFormatException(int code, int bufPos) { + errorCode = code; + bufferPosition = bufPos; +} +/** + * @return int + */ +public int getErrorCode() { + return errorCode; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/FieldInfo.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/FieldInfo.java new file mode 100644 index 0000000..fa7e164 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/FieldInfo.java @@ -0,0 +1,310 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.classfmt; + +import net.sourceforge.phpdt.internal.compiler.codegen.AttributeNamesConstants; +import net.sourceforge.phpdt.internal.compiler.env.IBinaryField; +import net.sourceforge.phpdt.internal.compiler.impl.BooleanConstant; +import net.sourceforge.phpdt.internal.compiler.impl.ByteConstant; +import net.sourceforge.phpdt.internal.compiler.impl.CharConstant; +import net.sourceforge.phpdt.internal.compiler.impl.Constant; +import net.sourceforge.phpdt.internal.compiler.impl.DoubleConstant; +import net.sourceforge.phpdt.internal.compiler.impl.FloatConstant; +import net.sourceforge.phpdt.internal.compiler.impl.IntConstant; +import net.sourceforge.phpdt.internal.compiler.impl.LongConstant; +import net.sourceforge.phpdt.internal.compiler.impl.ShortConstant; +import net.sourceforge.phpdt.internal.compiler.impl.StringConstant; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeIds; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class FieldInfo extends ClassFileStruct implements AttributeNamesConstants, IBinaryField, Comparable, TypeIds { + private Constant constant; + private boolean isDeprecated; + private boolean isSynthetic; + private int[] constantPoolOffsets; + private int accessFlags; + private char[] name; + private char[] signature; + private int attributesCount; + private int attributeBytes; + private Object wrappedConstantValue; +/** + * @param classFileBytes byte[] + * @param offsets int[] + * @param offset int + */ +public FieldInfo (byte classFileBytes[], int offsets[], int offset) throws ClassFormatException { + super(classFileBytes, offset); + constantPoolOffsets = offsets; + accessFlags = -1; + int attributesCount = u2At(6); + int readOffset = 8; + for (int i = 0; i < attributesCount; i++) { + readOffset += (6 + u4At(readOffset + 2)); + } + attributeBytes = readOffset; +} +/** + * Return the constant of the field. + * Return org.eclipse.jdt.internal.compiler.impl.Constant.NotAConstant if there is none. + * @return org.eclipse.jdt.internal.compiler.impl.Constant + */ +public Constant getConstant() { + if (constant == null) { + // read constant + readConstantAttribute(); + } + return constant; +} +/** + * Answer an int whose bits are set according the access constants + * defined by the VM spec. + * Set the AccDeprecated and AccSynthetic bits if necessary + * @return int + */ +public int getModifiers() { + if (accessFlags == -1) { + // compute the accessflag. Don't forget the deprecated attribute + accessFlags = u2At(0); + readDeprecatedAndSyntheticAttributes(); + if (isDeprecated) { + accessFlags |= AccDeprecated; + } + if (isSynthetic) { + accessFlags |= AccSynthetic; + } + } + return accessFlags; +} +/** + * Answer the name of the field. + * @return char[] + */ +public char[] getName() { + if (name == null) { + // read the name + int utf8Offset = constantPoolOffsets[u2At(2)] - structOffset; + name = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + } + return name; +} +/** + * Answer the resolved name of the receiver's type in the + * class file format as specified in section 4.3.2 of the Java 2 VM spec. + * + * For example: + * - java.lang.String is Ljava/lang/String; + * - an int is I + * - a 2 dimensional array of strings is [[Ljava/lang/String; + * - an array of floats is [F + * @return char[] + */ +public char[] getTypeName() { + if (signature == null) { + // read the signature + int utf8Offset = constantPoolOffsets[u2At(4)] - structOffset; + signature = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + } + return signature; +} +/** + * Return a wrapper that contains the constant of the field. + * Throws a java.ibm.compiler.java.classfmt.ClassFormatException in case the signature is + * incompatible with the constant tag. + * + * @exception java.ibm.compiler.java.classfmt.ClassFormatException + * @return java.lang.Object + */ +public Object getWrappedConstantValue() throws ClassFormatException { + + if (this.wrappedConstantValue == null) { + if (hasConstant()) { + Constant constant = getConstant(); + switch (constant.typeID()) { + case T_int : + this.wrappedConstantValue = new Integer(constant.intValue()); + break; + case T_byte : + this.wrappedConstantValue = new Byte(constant.byteValue()); + break; + case T_short : + this.wrappedConstantValue = new Short(constant.shortValue()); + break; + case T_char : + this.wrappedConstantValue = new Character(constant.charValue()); + break; + case T_float : + this.wrappedConstantValue = new Float(constant.floatValue()); + break; + case T_double : + this.wrappedConstantValue = new Double(constant.doubleValue()); + break; + case T_boolean : + this.wrappedConstantValue = new Boolean(constant.booleanValue()); + break; + case T_long : + this.wrappedConstantValue = new Long(constant.longValue()); + break; + case T_String : + this.wrappedConstantValue = constant.stringValue(); + } + } + } + return this.wrappedConstantValue; +} +/** + * Return true if the field has a constant value attribute, false otherwise. + * @return boolean + */ +public boolean hasConstant() { + return getConstant() != Constant.NotAConstant; +} +/** + * Return true if the field is a synthetic field, false otherwise. + * @return boolean + */ +public boolean isSynthetic() { + return (getModifiers() & AccSynthetic) != 0; +} + +private void readConstantAttribute() { + int attributesCount = u2At(6); + int readOffset = 8; + boolean isConstant = false; + for (int i = 0; i < attributesCount; i++) { + int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset; + char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + if (CharOperation + .equals(attributeName, ConstantValueName)) { + isConstant = true; + // read the right constant + int relativeOffset = constantPoolOffsets[u2At(readOffset + 6)] - structOffset; + switch (u1At(relativeOffset)) { + case IntegerTag : + char[] sign = getTypeName(); + if (sign.length == 1) { + switch (sign[0]) { + case 'Z' : // boolean constant + constant = new BooleanConstant(i4At(relativeOffset + 1) == 1); + break; + case 'I' : // integer constant + constant = new IntConstant(i4At(relativeOffset + 1)); + break; + case 'C' : // char constant + constant = new CharConstant((char) i4At(relativeOffset + 1)); + break; + case 'B' : // byte constant + constant = new ByteConstant((byte) i4At(relativeOffset + 1)); + break; + case 'S' : // short constant + constant = new ShortConstant((short) i4At(relativeOffset + 1)); + break; + default: + constant = Constant.NotAConstant; + } + } else { + constant = Constant.NotAConstant; + } + break; + case FloatTag : + constant = new FloatConstant(floatAt(relativeOffset + 1)); + break; + case DoubleTag : + constant = new DoubleConstant(doubleAt(relativeOffset + 1)); + break; + case LongTag : + constant = new LongConstant(i8At(relativeOffset + 1)); + break; + case StringTag : + utf8Offset = constantPoolOffsets[u2At(relativeOffset + 1)] - structOffset; + constant = + new StringConstant( + String.valueOf(utf8At(utf8Offset + 3, u2At(utf8Offset + 1)))); + break; + } + } + readOffset += (6 + u4At(readOffset + 2)); + } + if (!isConstant) { + constant = Constant.NotAConstant; + } +} +private void readDeprecatedAndSyntheticAttributes() { + int attributesCount = u2At(6); + int readOffset = 8; + for (int i = 0; i < attributesCount; i++) { + int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset; + char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + if (CharOperation.equals(attributeName, DeprecatedName)) { + isDeprecated = true; + } else if (CharOperation.equals(attributeName, SyntheticName)) { + isSynthetic = true; + } + readOffset += (6 + u4At(readOffset + 2)); + } +} +/** + * Answer the size of the receiver in bytes. + * + * @return int + */ +public int sizeInBytes() { + return attributeBytes; +} +public void throwFormatException() throws ClassFormatException { + throw new ClassFormatException(ClassFormatException.ErrBadFieldInfo); +} +public String toString() { + StringBuffer buffer = new StringBuffer(this.getClass().getName()); + int modifiers = getModifiers(); + return buffer + .append("{") //$NON-NLS-1$ + .append( + ((modifiers & AccDeprecated) != 0 ? "deprecated " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0001) == 1 ? "public " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0002) == 0x0002 ? "private " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0004) == 0x0004 ? "protected " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0008) == 0x000008 ? "static " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0010) == 0x0010 ? "final " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0040) == 0x0040 ? "volatile " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0080) == 0x0080 ? "transient " : "")) //$NON-NLS-1$ //$NON-NLS-2$ + .append(getTypeName()) + .append(" ") //$NON-NLS-1$ + .append(getName()) + .append(" ") //$NON-NLS-1$ + .append(getConstant()) + .append("}") //$NON-NLS-1$ + .toString(); +} + +public int compareTo(Object o) { + if (!(o instanceof FieldInfo)) { + throw new ClassCastException(); + } + return new String(this.getName()).compareTo(new String(((FieldInfo) o).getName())); +} +/** + * This method is used to fully initialize the contents of the receiver. All methodinfos, fields infos + * will be therefore fully initialized and we can get rid of the bytes. + */ +void initialize() { + getModifiers(); + getName(); + getConstant(); + getTypeName(); + reset(); +} +protected void reset() { + this.constantPoolOffsets = null; + super.reset(); +} + +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/InnerClassInfo.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/InnerClassInfo.java new file mode 100644 index 0000000..22963d0 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/InnerClassInfo.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.classfmt; + +import net.sourceforge.phpdt.internal.compiler.env.IBinaryNestedType; + +/** + * Describes one entry in the classes table of the InnerClasses attribute. + * See the inner class specification (The class file attribute "InnerClasses"). + */ + +public class InnerClassInfo extends ClassFileStruct implements IBinaryNestedType { + int innerClassNameIndex = -1; + int outerClassNameIndex = -1; + int innerNameIndex = -1; + private char[] innerClassName; + private char[] outerClassName; + private char[] innerName; + private int accessFlags = -1; + private int[] constantPoolOffsets; + private boolean readInnerClassName = false; + private boolean readOuterClassName = false; + private boolean readInnerName = false; +public InnerClassInfo(byte classFileBytes[], int offsets[], int offset) + throws ClassFormatException { + super(classFileBytes, offset); + constantPoolOffsets = offsets; + innerClassNameIndex = u2At(0); + outerClassNameIndex = u2At(2); + this.innerNameIndex = u2At(4); +} +/** + * Answer the resolved name of the enclosing type in the + * class file format as specified in section 4.2 of the Java 2 VM spec. + * + * For example, java.lang.String is java/lang/String. + * @return char[] + */ +public char[] getEnclosingTypeName() { + if (!readOuterClassName) { + // read outer class name + readOuterClassName = true; + if (outerClassNameIndex != 0) { + int utf8Offset = + constantPoolOffsets[u2At( + constantPoolOffsets[outerClassNameIndex] - structOffset + 1)] + - structOffset; + outerClassName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + } + + } + return outerClassName; +} +/** + * Answer an int whose bits are set according the access constants + * defined by the VM spec. + * @return int + */ +public int getModifiers() { + if (accessFlags == -1) { + // read access flag + accessFlags = u2At(6); + } + return accessFlags; +} +/** + * Answer the resolved name of the member type in the + * class file format as specified in section 4.2 of the Java 2 VM spec. + * + * For example, p1.p2.A.M is p1/p2/A$M. + * @return char[] + */ +public char[] getName() { + if (!readInnerClassName) { + // read the inner class name + readInnerClassName = true; + if (innerClassNameIndex != 0) { + int classOffset = constantPoolOffsets[innerClassNameIndex] - structOffset; + int utf8Offset = constantPoolOffsets[u2At(classOffset + 1)] - structOffset; + innerClassName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + } + } + return innerClassName; +} +/** + * Answer the source name of the member type. + * + * For example, p1.p2.A.M is M. + * @return char[] + */ +public char[] getSourceName() { + if (!this.readInnerName) { + this.readInnerName = true; + if (innerNameIndex != 0) { + int utf8Offset = constantPoolOffsets[innerNameIndex] - structOffset; + innerName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + } + } + return innerName; +} +/** + * Answer the string representation of the receiver + * @return java.lang.String + */ +public String toString() { + StringBuffer buffer = new StringBuffer(); + if (getName() != null) { + buffer.append(getName()); + } + buffer.append("\n"); //$NON-NLS-1$ + if (getEnclosingTypeName() != null) { + buffer.append(getEnclosingTypeName()); + } + buffer.append("\n"); //$NON-NLS-1$ + if (getSourceName() != null) { + buffer.append(getSourceName()); + } + return buffer.toString(); +} +/** + * This method is used to fully initialize the contents of the receiver. All methodinfos, fields infos + * will be therefore fully initialized and we can get rid of the bytes. + */ +void initialize() { + getModifiers(); + getName(); + getSourceName(); + getEnclosingTypeName(); + reset(); +} +protected void reset() { + this.constantPoolOffsets = null; + super.reset(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/MethodInfo.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/MethodInfo.java new file mode 100644 index 0000000..81be2c5 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/classfmt/MethodInfo.java @@ -0,0 +1,238 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.classfmt; + +import net.sourceforge.phpdt.internal.compiler.codegen.AttributeNamesConstants; +import net.sourceforge.phpdt.internal.compiler.env.IBinaryMethod; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class MethodInfo extends ClassFileStruct implements IBinaryMethod, AttributeNamesConstants, Comparable { + private char[][] exceptionNames; + private int[] constantPoolOffsets; + private boolean isDeprecated; + private boolean isSynthetic; + private int accessFlags; + private char[] name; + private char[] signature; + private int attributesCount; + private int attributeBytes; + static private final char[][] noException = new char[0][0]; + private int decodeIndex; +/** + * @param classFileBytes byte[] + * @param offsets int[] + * @param offset int + */ +public MethodInfo (byte classFileBytes[], int offsets[], int offset) throws ClassFormatException { + super(classFileBytes, offset); + constantPoolOffsets = offsets; + accessFlags = -1; + int attributesCount = u2At(6); + int readOffset = 8; + for (int i = 0; i < attributesCount; i++) { + readOffset += (6 + u4At(readOffset + 2)); + } + attributeBytes = readOffset; +} +/** + * @see IGenericMethod#getArgumentNames() + */ +public char[][] getArgumentNames() { + return null; +} +/** + * Answer the resolved names of the exception types in the + * class file format as specified in section 4.2 of the Java 2 VM spec + * or null if the array is empty. + * + * For example, java.lang.String is java/lang/String. + * @return char[][] + */ +public char[][] getExceptionTypeNames() { + if (exceptionNames == null) { + readExceptionAttributes(); + } + return exceptionNames; +} +/** + * Answer the receiver's method descriptor which describes the parameter & + * return types as specified in section 4.3.3 of the Java 2 VM spec. + * + * For example: + * - int foo(String) is (Ljava/lang/String;)I + * - void foo(Object[]) is (I)[Ljava/lang/Object; + * @return char[] + */ +public char[] getMethodDescriptor() { + if (signature == null) { + // read the name + int utf8Offset = constantPoolOffsets[u2At(4)] - structOffset; + signature = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + } + return signature; +} +/** + * Answer an int whose bits are set according the access constants + * defined by the VM spec. + * Set the AccDeprecated and AccSynthetic bits if necessary + * @return int + */ +public int getModifiers() { + if (accessFlags == -1) { + // compute the accessflag. Don't forget the deprecated attribute + accessFlags = u2At(0); + readDeprecatedAndSyntheticAttributes(); + if (isDeprecated) { + accessFlags |= AccDeprecated; + } + if (isSynthetic) { + accessFlags |= AccSynthetic; + } + } + return accessFlags; +} +/** + * Answer the name of the method. + * + * For a constructor, answer & for a clinit method. + * @return char[] + */ +public char[] getSelector() { + if (name == null) { + // read the name + int utf8Offset = constantPoolOffsets[u2At(2)] - structOffset; + name = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + } + return name; +} +/** + * Answer true if the method is a class initializer, false otherwise. + * @return boolean + */ +public boolean isClinit() { + char[] selector = getSelector(); + return selector[0] == '<' && selector.length == 8; // Can only match +} +/** + * Answer true if the method is a constructor, false otherwise. + * @return boolean + */ +public boolean isConstructor() { + char[] selector = getSelector(); + return selector[0] == '<' && selector.length == 6; // Can only match +} +/** + * Return true if the field is a synthetic method, false otherwise. + * @return boolean + */ +public boolean isSynthetic() { + return (getModifiers() & AccSynthetic) != 0; +} +private void readDeprecatedAndSyntheticAttributes() { + int attributesCount = u2At(6); + int readOffset = 8; + for (int i = 0; i < attributesCount; i++) { + int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset; + char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + if (CharOperation.equals(attributeName, DeprecatedName)) { + isDeprecated = true; + } else if (CharOperation.equals(attributeName, SyntheticName)) { + isSynthetic = true; + } + readOffset += (6 + u4At(readOffset + 2)); + } +} +private void readExceptionAttributes() { + int attributesCount = u2At(6); + int readOffset = 8; + for (int i = 0; i < attributesCount; i++) { + int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset; + char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + if (CharOperation.equals(attributeName, ExceptionsName)) { + // read the number of exception entries + int entriesNumber = u2At(readOffset + 6); + // place the readOffset at the beginning of the exceptions table + readOffset += 8; + if (entriesNumber == 0) { + exceptionNames = noException; + } else { + exceptionNames = new char[entriesNumber][]; + for (int j = 0; j < entriesNumber; j++) { + utf8Offset = + constantPoolOffsets[u2At( + constantPoolOffsets[u2At(readOffset)] - structOffset + 1)] + - structOffset; + exceptionNames[j] = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + readOffset += 2; + } + } + } else { + readOffset += (6 + u4At(readOffset + 2)); + } + } + if (exceptionNames == null) { + exceptionNames = noException; + } +} +/** + * Answer the size of the receiver in bytes. + * + * @return int + */ +public int sizeInBytes() { + return attributeBytes; +} +public String toString() { + int modifiers = getModifiers(); + StringBuffer buffer = new StringBuffer(this.getClass().getName()); + return buffer + .append("{") //$NON-NLS-1$ + .append( + ((modifiers & AccDeprecated) != 0 ? "deprecated " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0001) == 1 ? "public " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0002) == 0x0002 ? "private " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0004) == 0x0004 ? "protected " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0008) == 0x000008 ? "static " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0010) == 0x0010 ? "final " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0040) == 0x0040 ? "volatile " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0080) == 0x0080 ? "transient " : "")) //$NON-NLS-1$ //$NON-NLS-2$ + .append(getSelector()) + .append(getMethodDescriptor()) + .append("}") //$NON-NLS-1$ + .toString(); +} +public int compareTo(Object o) { + if (!(o instanceof MethodInfo)) { + throw new ClassCastException(); + } + + MethodInfo otherMethod = (MethodInfo) o; + int result = new String(this.getSelector()).compareTo(new String(otherMethod.getSelector())); + if (result != 0) return result; + return new String(this.getMethodDescriptor()).compareTo(new String(otherMethod.getMethodDescriptor())); +} + +/** + * This method is used to fully initialize the contents of the receiver. All methodinfos, fields infos + * will be therefore fully initialized and we can get rid of the bytes. + */ +void initialize() { + getModifiers(); + getSelector(); + getMethodDescriptor(); + getExceptionTypeNames(); + reset(); +} +protected void reset() { + this.constantPoolOffsets = null; + super.reset(); +} +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/AttributeNamesConstants.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/AttributeNamesConstants.java new file mode 100644 index 0000000..3662349 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/AttributeNamesConstants.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.codegen; + +public interface AttributeNamesConstants { + final char[] SyntheticName = new char[] {'S', 'y', 'n', 't', 'h', 'e', 't', 'i', 'c'}; + final char[] ConstantValueName = new char[] {'C', 'o', 'n', 's', 't', 'a', 'n', 't', 'V', 'a', 'l', 'u', 'e'}; + final char[] LineNumberTableName = new char[] {'L', 'i', 'n', 'e', 'N', 'u', 'm', 'b', 'e', 'r', 'T', 'a', 'b', 'l', 'e'}; + final char[] LocalVariableTableName = new char[] {'L', 'o', 'c', 'a', 'l', 'V', 'a', 'r', 'i', 'a', 'b', 'l', 'e', 'T', 'a', 'b', 'l', 'e'}; + final char[] InnerClassName = new char[] {'I', 'n', 'n', 'e', 'r', 'C', 'l', 'a', 's', 's', 'e', 's'}; + final char[] CodeName = new char[] {'C', 'o', 'd', 'e'}; + final char[] ExceptionsName = new char[] {'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n', 's'}; + final char[] SourceName = new char[] {'S', 'o', 'u', 'r', 'c', 'e', 'F', 'i', 'l', 'e'}; + final char[] DeprecatedName = new char[] {'D', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd'}; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/CaseLabel.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/CaseLabel.java new file mode 100644 index 0000000..218208a --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/CaseLabel.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.codegen; + +public class CaseLabel extends Label { + public int instructionPosition = POS_NOT_SET; + public int backwardsBranch = POS_NOT_SET; +/** + * CaseLabel constructor comment. + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ +public CaseLabel(CodeStream codeStream) { + super(codeStream); +} +/* +* Put down a refernece to the array at the location in the codestream. +*/ +void branch() { + if (position == POS_NOT_SET) { + addForwardReference(codeStream.position); + // Leave 4 bytes free to generate the jump offset afterwards + codeStream.position += 4; + codeStream.classFileOffset += 4; + } else { //Position is set. Write it! + codeStream.writeSignedWord(position - codeStream.position + 1); + } +} +/* +* Put down a refernece to the array at the location in the codestream. +*/ +void branchWide() { + if (position == POS_NOT_SET) { + addForwardReference(codeStream.position); + // Leave 4 bytes free to generate the jump offset afterwards + codeStream.position += 4; + } else { //Position is set. Write it! + codeStream.writeSignedWord(position - codeStream.position + 1); + } +} +public boolean isStandardLabel(){ + return false; +} +/* +* Put down a reference to the array at the location in the codestream. +*/ +public void place() { + position = codeStream.position; + if (instructionPosition == POS_NOT_SET) + backwardsBranch = position; + else { + int offset = position - instructionPosition; + for (int i = 0; i < forwardReferenceCount; i++) { + codeStream.writeSignedWord(forwardReferences[i], offset); + } + // add the label int the codeStream labels collection + codeStream.addLabel(this); + } +} +/* +* Put down a refernece to the array at the location in the codestream. +*/ +void placeInstruction() { + if (instructionPosition == POS_NOT_SET) { + instructionPosition = codeStream.position; + if (backwardsBranch != POS_NOT_SET) { + int offset = backwardsBranch - instructionPosition; + for (int i = 0; i < forwardReferenceCount; i++) + codeStream.writeSignedWord(forwardReferences[i], offset); + backwardsBranch = POS_NOT_SET; + } + } +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/CharArrayCache.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/CharArrayCache.java new file mode 100644 index 0000000..cef0d81 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/CharArrayCache.java @@ -0,0 +1,184 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.codegen; + +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class CharArrayCache { + // to avoid using Enumerations, walk the individual tables skipping nulls + public char[] keyTable[]; + public int valueTable[]; + int elementSize; // number of elements in the table + int threshold; +/** + * Constructs a new, empty hashtable. A default capacity is used. + * Note that the hashtable will automatically grow when it gets full. + */ +public CharArrayCache() { + this(13); +} +/** + * Constructs a new, empty hashtable with the specified initial + * capacity. + * @param initialCapacity int + * the initial number of buckets + */ +public CharArrayCache(int initialCapacity) { + this.elementSize = 0; + this.threshold = (int) (initialCapacity * 0.66f); + this.keyTable = new char[initialCapacity][]; + this.valueTable = new int[initialCapacity]; +} +/** + * Clears the hash table so that it has no more elements in it. + */ +public void clear() { + for (int i = keyTable.length; --i >= 0;) { + keyTable[i] = null; + valueTable[i] = 0; + } + elementSize = 0; +} +/** Returns true if the collection contains an element for the key. + * + * @param char[] key the key that we are looking for + * @return boolean + */ +public boolean containsKey(char[] key) { + int index = hashCodeChar(key); + while (keyTable[index] != null) { + if (CharOperation.equals(keyTable[index], key)) + return true; + index = (index + 1) % keyTable.length; + } + return false; +} +/** Gets the object associated with the specified key in the + * hashtable. + * @param key char[] the specified key + * @return int the element for the key or -1 if the key is not + * defined in the hash table. + */ +public int get(char[] key) { + int index = hashCodeChar(key); + while (keyTable[index] != null) { + if (CharOperation.equals(keyTable[index], key)) + return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return -1; +} +private int hashCodeChar(char[] val) { + int length = val.length; + int hash = 0; + int n = 2; // number of characters skipped + for (int i = 0; i < length; i += n) { + hash += val[i]; + } + return (hash & 0x7FFFFFFF) % keyTable.length; +} +/** + * Puts the specified element into the hashtable, using the specified + * key. The element may be retrieved by doing a get() with the same key. + * The key and the element cannot be null. + * + * @param key Object the specified key in the hashtable + * @param value int the specified element + * @return int the old value of the key, or -1 if it did not have one. + */ +public int put(char[] key, int value) { + int index = hashCodeChar(key); + while (keyTable[index] != null) { + if (CharOperation.equals(keyTable[index], key)) + return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) + rehash(); + return value; +} +/** + * Rehashes the content of the table into a bigger table. + * This method is called automatically when the hashtable's + * size exceeds the threshold. + */ +private void rehash() { + CharArrayCache newHashtable = new CharArrayCache(keyTable.length * 2); + for (int i = keyTable.length; --i >= 0;) + if (keyTable[i] != null) + newHashtable.put(keyTable[i], valueTable[i]); + + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; +} +/** Remove the object associated with the specified key in the + * hashtable. + * @param key char[] the specified key + */ +public void remove(char[] key) { + int index = hashCodeChar(key); + while (keyTable[index] != null) { + if (CharOperation.equals(keyTable[index], key)) { + valueTable[index] = 0; + keyTable[index] = null; + return; + } + index = (index + 1) % keyTable.length; + } +} +/** + * Returns the key corresponding to the value. Returns null if the + * receiver doesn't contain the value. + * @param value int the value that we are looking for + * @return Object + */ +public char[] returnKeyFor(int value) { + for (int i = keyTable.length; i-- > 0;) { + if (valueTable[i] == value) { + return keyTable[i]; + } + } + return null; +} +/** + * Returns the number of elements contained in the hashtable. + * + * @return int The size of the table + */ +public int size() { + return elementSize; +} +/** + * Converts to a rather lengthy String. + * + * return String the ascii representation of the receiver + */ +public String toString() { + int max = size(); + StringBuffer buf = new StringBuffer(); + buf.append("{"); //$NON-NLS-1$ + for (int i = 0; i < max; ++i) { + if (keyTable[i] != null) { + buf.append(keyTable[i]).append("->").append(valueTable[i]); //$NON-NLS-1$ + } + if (i < max) { + buf.append(", "); //$NON-NLS-1$ + } + } + buf.append("}"); //$NON-NLS-1$ + return buf.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/CodeStream.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/CodeStream.java new file mode 100644 index 0000000..52d6b86 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/CodeStream.java @@ -0,0 +1,5690 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.codegen; + +import net.sourceforge.phpdt.internal.compiler.*; + +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.classfmt.*; +import net.sourceforge.phpdt.internal.compiler.flow.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class CodeStream implements OperatorIds, ClassFileConstants, Opcodes, BaseTypes, TypeConstants, TypeIds { + // It will be responsible for the following items. + + // -> Tracking Max Stack. + + public int stackMax; // Use Ints to keep from using extra bc when adding + public int stackDepth; // Use Ints to keep from using extra bc when adding + public int maxLocals; + public static final int max = 100; // Maximum size of the code array + public static final int growFactor = 400; + public static final int LABELS_INCREMENT = 5; + public byte[] bCodeStream; + public int pcToSourceMapSize; + public int[] pcToSourceMap = new int[24]; + public int lastEntryPC; // last entry recorded + public int[] lineSeparatorPositions; + public int position; // So when first set can be incremented + public int classFileOffset; + public int startingClassFileOffset; // I need to keep the starting point inside the byte array + public ConstantPool constantPool; // The constant pool used to generate bytecodes that need to store information into the constant pool + public ClassFile classFile; // The current classfile it is associated to. + // local variable attributes output + public static final int LOCALS_INCREMENT = 10; + public LocalVariableBinding[] locals = new LocalVariableBinding[LOCALS_INCREMENT]; + static LocalVariableBinding[] noLocals = new LocalVariableBinding[LOCALS_INCREMENT]; + public LocalVariableBinding[] visibleLocals = new LocalVariableBinding[LOCALS_INCREMENT]; + static LocalVariableBinding[] noVisibleLocals = new LocalVariableBinding[LOCALS_INCREMENT]; + int visibleLocalsCount; + public AbstractMethodDeclaration methodDeclaration; + public ExceptionLabel[] exceptionHandlers = new ExceptionLabel[LABELS_INCREMENT]; + static ExceptionLabel[] noExceptionHandlers = new ExceptionLabel[LABELS_INCREMENT]; + public int exceptionHandlersNumber; + public static FieldBinding[] ImplicitThis = new FieldBinding[] {}; + public boolean generateLineNumberAttributes; + public boolean generateLocalVariableTableAttributes; + public boolean preserveUnusedLocals; + // store all the labels placed at the current position to be able to optimize + // a jump to the next bytecode. + public Label[] labels = new Label[LABELS_INCREMENT]; + static Label[] noLabels = new Label[LABELS_INCREMENT]; + public int countLabels; + public int allLocalsCounter; + public int maxFieldCount; + // to handle goto_w + public boolean wideMode = false; + public static final CompilationResult RESTART_IN_WIDE_MODE = new CompilationResult((char[])null, 0, 0, 0); + +public CodeStream(ClassFile classFile) { + generateLineNumberAttributes = (classFile.produceDebugAttributes & CompilerOptions.Lines) != 0; + generateLocalVariableTableAttributes = (classFile.produceDebugAttributes & CompilerOptions.Vars) != 0; + if (generateLineNumberAttributes) { + lineSeparatorPositions = classFile.referenceBinding.scope.referenceCompilationUnit().compilationResult.lineSeparatorPositions; + } +} +final public void aaload() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_aaload; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_aaload); + } +} +final public void aastore() { + countLabels = 0; + stackDepth -= 3; + try { + position++; + bCodeStream[classFileOffset++] = OPC_aastore; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_aastore); + } +} +final public void aconst_null() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_aconst_null; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_aconst_null); + } +} +public final void addDefinitelyAssignedVariables(Scope scope, int initStateIndex) { + // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect + if (!generateLocalVariableTableAttributes) + return; +/* if (initStateIndex == lastInitStateIndexWhenAddingInits) + return; + lastInitStateIndexWhenAddingInits = initStateIndex; + if (lastInitStateIndexWhenRemovingInits != initStateIndex){ + lastInitStateIndexWhenRemovingInits = -2; // reinitialize remove index + // remove(1)-add(1)-remove(1) -> ignore second remove + // remove(1)-add(2)-remove(1) -> perform second remove + } + +*/ for (int i = 0; i < visibleLocalsCount; i++) { + LocalVariableBinding localBinding = visibleLocals[i]; + if (localBinding != null) { + // Check if the local is definitely assigned + if ((initStateIndex != -1) && isDefinitelyAssigned(scope, initStateIndex, localBinding)) { + if ((localBinding.initializationCount == 0) || (localBinding.initializationPCs[((localBinding.initializationCount - 1) << 1) + 1] != -1)) { + /* There are two cases: + * 1) there is no initialization interval opened ==> add an opened interval + * 2) there is already some initialization intervals but the last one is closed ==> add an opened interval + * An opened interval means that the value at localBinding.initializationPCs[localBinding.initializationCount - 1][1] + * is equals to -1. + * initializationPCs is a collection of pairs of int: + * first value is the startPC and second value is the endPC. -1 one for the last value means that the interval + * is not closed yet. + */ + localBinding.recordInitializationStartPC(position); + } + } + } + } +} +public void addLabel(Label aLabel) { + if (countLabels == labels.length) + System.arraycopy(labels, 0, (labels = new Label[countLabels + LABELS_INCREMENT]), 0, countLabels); + labels[countLabels++] = aLabel; +} +public void addVisibleLocalVariable(LocalVariableBinding localBinding) { + if (!generateLocalVariableTableAttributes) + return; + + if (visibleLocalsCount >= visibleLocals.length) { + System.arraycopy(visibleLocals, 0, (visibleLocals = new LocalVariableBinding[visibleLocalsCount * 2]), 0, visibleLocalsCount); + } + visibleLocals[visibleLocalsCount++] = localBinding; +} +final public void aload(int iArg) { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (maxLocals <= iArg) { + maxLocals = iArg + 1; + } + if (iArg > 255) { // Widen + try { + position++; + bCodeStream[classFileOffset++] = OPC_wide; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_wide); + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_aload; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_aload); + } + writeUnsignedShort(iArg); + } else { + // Don't need to use the wide bytecode + try { + position++; + bCodeStream[classFileOffset++] = OPC_aload; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_aload); + } + try { + position++; + bCodeStream[classFileOffset++] = (byte) (iArg); + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) iArg); + } + } +} +final public void aload_0() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (maxLocals == 0) { + maxLocals = 1; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_aload_0; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_aload_0); + } +} +final public void aload_1() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (maxLocals <= 1) { + maxLocals = 2; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_aload_1; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_aload_1); + } +} +final public void aload_2() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (maxLocals <= 2) { + maxLocals = 3; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_aload_2; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_aload_2); + } +} +final public void aload_3() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (maxLocals <= 3) { + maxLocals = 4; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_aload_3; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_aload_3); + } +} +public final void anewarray(TypeBinding typeBinding) { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_anewarray; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_anewarray); + } + writeUnsignedShort(constantPool.literalIndex(typeBinding)); +} +public void anewarrayJavaLangClass() { + // anewarray: java.lang.Class + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_anewarray; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_anewarray); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangClass()); +} +public void anewarrayJavaLangObject() { + // anewarray: java.lang.Object + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_anewarray; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_anewarray); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangObject()); +} +final public void areturn() { + countLabels = 0; + stackDepth--; + // the stackDepth should be equal to 0 + try { + position++; + bCodeStream[classFileOffset++] = OPC_areturn; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_areturn); + } +} +public void arrayAt(int typeBindingID) { + switch (typeBindingID) { + case T_int : + this.iaload(); + break; + case T_byte : + case T_boolean : + this.baload(); + break; + case T_short : + this.saload(); + break; + case T_char : + this.caload(); + break; + case T_long : + this.laload(); + break; + case T_float : + this.faload(); + break; + case T_double : + this.daload(); + break; + default : + this.aaload(); + } +} +public void arrayAtPut(int elementTypeID, boolean valueRequired) { + switch (elementTypeID) { + case T_int : + if (valueRequired) + dup_x2(); + iastore(); + break; + case T_byte : + case T_boolean : + if (valueRequired) + dup_x2(); + bastore(); + break; + case T_short : + if (valueRequired) + dup_x2(); + sastore(); + break; + case T_char : + if (valueRequired) + dup_x2(); + castore(); + break; + case T_long : + if (valueRequired) + dup2_x2(); + lastore(); + break; + case T_float : + if (valueRequired) + dup_x2(); + fastore(); + break; + case T_double : + if (valueRequired) + dup2_x2(); + dastore(); + break; + default : + if (valueRequired) + dup_x2(); + aastore(); + } +} +final public void arraylength() { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_arraylength; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_arraylength); + } +} +final public void astore(int iArg) { + countLabels = 0; + stackDepth--; + if (maxLocals <= iArg) { + maxLocals = iArg + 1; + } + if (iArg > 255) { // Widen + try { + position++; + bCodeStream[classFileOffset++] = OPC_wide; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_wide); + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_astore; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_astore); + } + writeUnsignedShort(iArg); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_astore; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_astore); + } + try { + position++; + bCodeStream[classFileOffset++] = (byte) iArg; + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) iArg); + } + } +} +final public void astore_0() { + countLabels = 0; + stackDepth--; + if (maxLocals == 0) { + maxLocals = 1; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_astore_0; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_astore_0); + } +} +final public void astore_1() { + countLabels = 0; + stackDepth--; + if (maxLocals <= 1) { + maxLocals = 2; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_astore_1; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_astore_1); + } +} +final public void astore_2() { + countLabels = 0; + stackDepth--; + if (maxLocals <= 2) { + maxLocals = 3; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_astore_2; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_astore_2); + } +} +final public void astore_3() { + countLabels = 0; + stackDepth--; + if (maxLocals <= 3) { + maxLocals = 4; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_astore_3; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_astore_3); + } +} +final public void athrow() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_athrow; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_athrow); + } +} +final public void baload() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_baload; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_baload); + } +} +final public void bastore() { + countLabels = 0; + stackDepth -= 3; + try { + position++; + bCodeStream[classFileOffset++] = OPC_bastore; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_bastore); + } +} +final public void bipush(byte b) { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_bipush; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_bipush); + } + writeSignedByte(b); +} +final public void caload() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_caload; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_caload); + } +} +final public void castore() { + countLabels = 0; + stackDepth -= 3; + try { + position++; + bCodeStream[classFileOffset++] = OPC_castore; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_castore); + } +} +public final void checkcast(TypeBinding typeBinding) { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_checkcast; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_checkcast); + } + writeUnsignedShort(constantPool.literalIndex(typeBinding)); +} +public final void checkcastJavaLangError() { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_checkcast; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_checkcast); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangError()); +} +final public void d2f() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_d2f; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_d2f); + } +} +final public void d2i() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_d2i; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_d2i); + } +} +final public void d2l() { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_d2l; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_d2l); + } +} +final public void dadd() { + countLabels = 0; + stackDepth -= 2; + try { + position++; + bCodeStream[classFileOffset++] = OPC_dadd; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dadd); + } +} +final public void daload() { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_daload; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_daload); + } +} +final public void dastore() { + countLabels = 0; + stackDepth -= 4; + try { + position++; + bCodeStream[classFileOffset++] = OPC_dastore; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dastore); + } +} +final public void dcmpg() { + countLabels = 0; + stackDepth -= 3; + try { + position++; + bCodeStream[classFileOffset++] = OPC_dcmpg; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dcmpg); + } +} +final public void dcmpl() { + countLabels = 0; + stackDepth -= 3; + try { + position++; + bCodeStream[classFileOffset++] = OPC_dcmpl; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dcmpl); + } +} +final public void dconst_0() { + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_dconst_0; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dconst_0); + } +} +final public void dconst_1() { + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_dconst_1; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dconst_1); + } +} +final public void ddiv() { + countLabels = 0; + stackDepth -= 2; + try { + position++; + bCodeStream[classFileOffset++] = OPC_ddiv; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ddiv); + } +} +public void decrStackSize(int offset) { + stackDepth -= offset; +} +final public void dload(int iArg) { + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (maxLocals < iArg + 2) { + maxLocals = iArg + 2; // + 2 because it is a double + } + if (iArg > 255) { // Widen + try { + position++; + bCodeStream[classFileOffset++] = OPC_wide; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_wide); + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_dload; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dload); + } + writeUnsignedShort(iArg); + } else { + // Don't need to use the wide bytecode + try { + position++; + bCodeStream[classFileOffset++] = OPC_dload; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dload); + } + try { + position++; + bCodeStream[classFileOffset++] = (byte) iArg; + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) iArg); + } + } +} +final public void dload_0() { + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (maxLocals < 2) { + maxLocals = 2; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_dload_0; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dload_0); + } +} +final public void dload_1() { + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (maxLocals < 3) { + maxLocals = 3; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_dload_1; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dload_1); + } +} +final public void dload_2() { + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (maxLocals < 4) { + maxLocals = 4; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_dload_2; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dload_2); + } +} +final public void dload_3() { + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (maxLocals < 5) { + maxLocals = 5; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_dload_3; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dload_3); + } +} +final public void dmul() { + countLabels = 0; + stackDepth -= 2; + try { + position++; + bCodeStream[classFileOffset++] = OPC_dmul; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dmul); + } +} +final public void dneg() { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_dneg; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dneg); + } +} +final public void drem() { + countLabels = 0; + stackDepth -= 2; + try { + position++; + bCodeStream[classFileOffset++] = OPC_drem; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_drem); + } +} +final public void dreturn() { + countLabels = 0; + stackDepth -= 2; + // the stackDepth should be equal to 0 + try { + position++; + bCodeStream[classFileOffset++] = OPC_dreturn; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dreturn); + } +} +final public void dstore(int iArg) { + countLabels = 0; + stackDepth -= 2; + if (maxLocals <= iArg + 1) { + maxLocals = iArg + 2; + } + if (iArg > 255) { // Widen + try { + position++; + bCodeStream[classFileOffset++] = OPC_wide; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_wide); + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_dstore; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dstore); + } + writeUnsignedShort(iArg); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_dstore; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dstore); + } + try { + position++; + bCodeStream[classFileOffset++] = (byte) iArg; + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) iArg); + } + } +} +final public void dstore_0() { + countLabels = 0; + stackDepth -= 2; + if (maxLocals < 2) { + maxLocals = 2; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_dstore_0; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dstore_0); + } +} +final public void dstore_1() { + countLabels = 0; + stackDepth -= 2; + if (maxLocals < 3) { + maxLocals = 3; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_dstore_1; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dstore_1); + } +} +final public void dstore_2() { + countLabels = 0; + stackDepth -= 2; + if (maxLocals < 4) { + maxLocals = 4; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_dstore_2; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dstore_2); + } +} +final public void dstore_3() { + countLabels = 0; + stackDepth -= 2; + if (maxLocals < 5) { + maxLocals = 5; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_dstore_3; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dstore_3); + } +} +final public void dsub() { + countLabels = 0; + stackDepth -= 2; + try { + position++; + bCodeStream[classFileOffset++] = OPC_dsub; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dsub); + } +} +final public void dup() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_dup; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dup); + } +} +final public void dup_x1() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_dup_x1; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dup_x1); + } +} +final public void dup_x2() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_dup_x2; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dup_x2); + } +} +final public void dup2() { + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_dup2; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dup2); + } +} +final public void dup2_x1() { + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_dup2_x1; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dup2_x1); + } +} +final public void dup2_x2() { + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_dup2_x2; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_dup2_x2); + } +} +public void exitUserScope(BlockScope blockScope) { + // mark all the scope's locals as loosing their definite assignment + + if (!generateLocalVariableTableAttributes) + return; + for (int i = 0; i < visibleLocalsCount; i++) { + LocalVariableBinding visibleLocal = visibleLocals[i]; + if ((visibleLocal != null) && (visibleLocal.declaringScope == blockScope)) { + // there maybe some some preserved locals never initialized + if (visibleLocal.initializationCount > 0){ + visibleLocals[i].recordInitializationEndPC(position); + } + visibleLocals[i] = null; // this variable is no longer visible afterwards + } + } +} +final public void f2d() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_f2d; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_f2d); + } +} +final public void f2i() { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_f2i; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_f2i); + } +} +final public void f2l() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_f2l; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_f2l); + } +} +final public void fadd() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_fadd; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fadd); + } +} +final public void faload() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_faload; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_faload); + } +} +final public void fastore() { + countLabels = 0; + stackDepth -= 3; + try { + position++; + bCodeStream[classFileOffset++] = OPC_fastore; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fastore); + } +} +final public void fcmpg() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_fcmpg; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fcmpg); + } +} +final public void fcmpl() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_fcmpl; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fcmpl); + } +} +final public void fconst_0() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_fconst_0; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fconst_0); + } +} +final public void fconst_1() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_fconst_1; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fconst_1); + } +} +final public void fconst_2() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_fconst_2; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fconst_2); + } +} +final public void fdiv() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_fdiv; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fdiv); + } +} +final public void fload(int iArg) { + countLabels = 0; + stackDepth++; + if (maxLocals <= iArg) { + maxLocals = iArg + 1; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + if (iArg > 255) { // Widen + try { + position++; + bCodeStream[classFileOffset++] = OPC_wide; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_wide); + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_fload; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fload); + } + writeUnsignedShort(iArg); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_fload; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fload); + } + try { + position++; + bCodeStream[classFileOffset++] = (byte) iArg; + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) iArg); + } + } +} +final public void fload_0() { + countLabels = 0; + stackDepth++; + if (maxLocals == 0) { + maxLocals = 1; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_fload_0; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fload_0); + } +} +final public void fload_1() { + countLabels = 0; + stackDepth++; + if (maxLocals <= 1) { + maxLocals = 2; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_fload_1; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fload_1); + } +} +final public void fload_2() { + countLabels = 0; + stackDepth++; + if (maxLocals <= 2) { + maxLocals = 3; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_fload_2; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fload_2); + } +} +final public void fload_3() { + countLabels = 0; + stackDepth++; + if (maxLocals <= 3) { + maxLocals = 4; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_fload_3; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fload_3); + } +} +final public void fmul() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_fmul; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fmul); + } +} +final public void fneg() { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_fneg; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fneg); + } +} +final public void frem() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_frem; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_frem); + } +} +final public void freturn() { + countLabels = 0; + stackDepth--; + // the stackDepth should be equal to 0 + try { + position++; + bCodeStream[classFileOffset++] = OPC_freturn; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_freturn); + } +} +final public void fstore(int iArg) { + countLabels = 0; + stackDepth--; + if (maxLocals <= iArg) { + maxLocals = iArg + 1; + } + if (iArg > 255) { // Widen + try { + position++; + bCodeStream[classFileOffset++] = OPC_wide; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_wide); + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_fstore; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fstore); + } + writeUnsignedShort(iArg); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_fstore; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fstore); + } + try { + position++; + bCodeStream[classFileOffset++] = (byte) iArg; + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) iArg); + } + } +} +final public void fstore_0() { + countLabels = 0; + stackDepth--; + if (maxLocals == 0) { + maxLocals = 1; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_fstore_0; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fstore_0); + } +} +final public void fstore_1() { + countLabels = 0; + stackDepth--; + if (maxLocals <= 1) { + maxLocals = 2; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_fstore_1; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fstore_1); + } +} +final public void fstore_2() { + countLabels = 0; + stackDepth--; + if (maxLocals <= 2) { + maxLocals = 3; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_fstore_2; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fstore_2); + } +} +final public void fstore_3() { + countLabels = 0; + stackDepth--; + if (maxLocals <= 3) { + maxLocals = 4; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_fstore_3; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fstore_3); + } +} +final public void fsub() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_fsub; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_fsub); + } +} +/** + * Macro for building a class descriptor object + */ +public void generateClassLiteralAccessForType(TypeBinding accessedType, FieldBinding syntheticFieldBinding) { + Label endLabel; + ExceptionLabel anyExceptionHandler; + int saveStackSize; + if (accessedType.isBaseType() && accessedType != NullBinding) { + this.getTYPE(accessedType.id); + return; + } + endLabel = new Label(this); + + if (syntheticFieldBinding != null) { // non interface case + this.getstatic(syntheticFieldBinding); + this.dup(); + this.ifnonnull(endLabel); + this.pop(); + } + + /* Macro for building a class descriptor object... using or not a field cache to store it into... + this sequence is responsible for building the actual class descriptor. + + If the fieldCache is set, then it is supposed to be the body of a synthetic access method + factoring the actual descriptor creation out of the invocation site (saving space). + If the fieldCache is nil, then we are dumping the bytecode on the invocation site, since + we have no way to get a hand on the field cache to do better. */ + + + // Wrap the code in an exception handler to convert a ClassNotFoundException into a NoClassDefError + + anyExceptionHandler = new ExceptionLabel(this, TypeBinding.NullBinding /* represents ClassNotFoundException*/); + this.ldc(accessedType == TypeBinding.NullBinding ? "java.lang.Object" : String.valueOf(accessedType.constantPoolName()).replace('/', '.')); //$NON-NLS-1$ + this.invokeClassForName(); + + /* We need to protect the runtime code from binary inconsistencies + in case the accessedType is missing, the ClassNotFoundException has to be converted + into a NoClassDefError(old ex message), we thus need to build an exception handler for this one. */ + anyExceptionHandler.placeEnd(); + + if (syntheticFieldBinding != null) { // non interface case + this.dup(); + this.putstatic(syntheticFieldBinding); + } + this.goto_(endLabel); + + + // Generate the body of the exception handler + saveStackSize = stackDepth; + stackDepth = 1; + /* ClassNotFoundException on stack -- the class literal could be doing more things + on the stack, which means that the stack may not be empty at this point in the + above code gen. So we save its state and restart it from 1. */ + + anyExceptionHandler.place(); + + // Transform the current exception, and repush and throw a + // NoClassDefFoundError(ClassNotFound.getMessage()) + + this.newNoClassDefFoundError(); + this.dup_x1(); + this.swap(); + + // Retrieve the message from the old exception + this.invokeThrowableGetMessage(); + + // Send the constructor taking a message string as an argument + this.invokeNoClassDefFoundErrorStringConstructor(); + this.athrow(); + endLabel.place(); + stackDepth = saveStackSize; +} +/** + * This method returns the exception handler to be able to generate the exception handler + * attribute. + */ +final public int[] generateCodeAttributeForProblemMethod(String errorName, String problemMessage) { + /** + * Equivalent code: + * try { + * throw ((Error) (Class.forName(errorName).getConstructor(new Class[] {Class.forName("java.lang.String")})).newInstance(new Object[] {problemMessage})); + * } catch (Exception e) { + * throw (NullPointerException) null; + * } + */ + int endPC, handlerPC; + ldc(errorName); + invokeClassForName(); + iconst_1(); + anewarrayJavaLangClass(); + dup(); + iconst_0(); + ldc("java.lang.String"); //$NON-NLS-1$ + invokeClassForName(); + aastore(); + invokeConstructorGetConstructor(); + iconst_1(); + anewarrayJavaLangObject(); + dup(); + iconst_0(); + ldc(problemMessage); + aastore(); + invokeObjectNewInstance(); + checkcastJavaLangError(); + athrow(); + endPC = handlerPC = position; + pop(); + aconst_null(); + athrow(); + return_(); + return new int[] {0, endPC, handlerPC}; +} +public void generateConstant(Constant constant, int implicitConversionCode) { + int targetTypeID = implicitConversionCode >> 4; + switch (targetTypeID) { + case T_boolean : + generateInlinedValue(constant.booleanValue()); + break; + case T_char : + generateInlinedValue(constant.charValue()); + break; + case T_byte : + generateInlinedValue(constant.byteValue()); + break; + case T_short : + generateInlinedValue(constant.shortValue()); + break; + case T_int : + generateInlinedValue(constant.intValue()); + break; + case T_long : + generateInlinedValue(constant.longValue()); + break; + case T_float : + generateInlinedValue(constant.floatValue()); + break; + case T_double : + generateInlinedValue(constant.doubleValue()); + break; + case T_String : + this.ldc(constant.stringValue()); + break; + default : //reference object (constant can be from T_null or T_String) + if (constant.typeID() == T_String) + ldc(constant.stringValue()); + else + aconst_null(); + } +} +/** + * @param implicitConversionCode int + */ +public void generateImplicitConversion(int implicitConversionCode) { + switch (implicitConversionCode) { + case Float2Char : + this.f2i(); + this.i2c(); + break; + case Double2Char : + this.d2i(); + this.i2c(); + break; + case Int2Char : + case Short2Char : + case Byte2Char : + this.i2c(); + break; + case Long2Char : + this.l2i(); + this.i2c(); + break; + case Char2Float : + case Short2Float : + case Int2Float : + case Byte2Float : + this.i2f(); + break; + case Double2Float : + this.d2f(); + break; + case Long2Float : + this.l2f(); + break; + case Float2Byte : + this.f2i(); + this.i2b(); + break; + case Double2Byte : + this.d2i(); + this.i2b(); + break; + case Int2Byte : + case Short2Byte : + case Char2Byte : + this.i2b(); + break; + case Long2Byte : + this.l2i(); + this.i2b(); + break; + case Byte2Double : + case Char2Double : + case Short2Double : + case Int2Double : + this.i2d(); + break; + case Float2Double : + this.f2d(); + break; + case Long2Double : + this.l2d(); + break; + case Byte2Short : + case Char2Short : + case Int2Short : + this.i2s(); + break; + case Double2Short : + this.d2i(); + this.i2s(); + break; + case Long2Short : + this.l2i(); + this.i2s(); + break; + case Float2Short : + this.f2i(); + this.i2s(); + break; + case Double2Int : + this.d2i(); + break; + case Float2Int : + this.f2i(); + break; + case Long2Int : + this.l2i(); + break; + case Int2Long : + case Char2Long : + case Byte2Long : + case Short2Long : + this.i2l(); + break; + case Double2Long : + this.d2l(); + break; + case Float2Long : + this.f2l(); + } +} +public void generateInlinedValue(byte inlinedValue) { + switch (inlinedValue) { + case -1 : + this.iconst_m1(); + break; + case 0 : + this.iconst_0(); + break; + case 1 : + this.iconst_1(); + break; + case 2 : + this.iconst_2(); + break; + case 3 : + this.iconst_3(); + break; + case 4 : + this.iconst_4(); + break; + case 5 : + this.iconst_5(); + break; + default : + if ((-128 <= inlinedValue) && (inlinedValue <= 127)) { + this.bipush((byte) inlinedValue); + return; + } + } +} +public void generateInlinedValue(char inlinedValue) { + switch (inlinedValue) { + case 0 : + this.iconst_0(); + break; + case 1 : + this.iconst_1(); + break; + case 2 : + this.iconst_2(); + break; + case 3 : + this.iconst_3(); + break; + case 4 : + this.iconst_4(); + break; + case 5 : + this.iconst_5(); + break; + default : + if ((6 <= inlinedValue) && (inlinedValue <= 127)) { + this.bipush((byte) inlinedValue); + return; + } + if ((128 <= inlinedValue) && (inlinedValue <= 32767)) { + this.sipush(inlinedValue); + return; + } + this.ldc(inlinedValue); + } +} +public void generateInlinedValue(double inlinedValue) { + if (inlinedValue == 0.0) { + if (Double.doubleToLongBits(inlinedValue) != 0L) + this.ldc2_w(inlinedValue); + else + this.dconst_0(); + return; + } + if (inlinedValue == 1.0) { + this.dconst_1(); + return; + } + this.ldc2_w(inlinedValue); +} +public void generateInlinedValue(float inlinedValue) { + if (inlinedValue == 0.0f) { + if (Float.floatToIntBits(inlinedValue) != 0) + this.ldc(inlinedValue); + else + this.fconst_0(); + return; + } + if (inlinedValue == 1.0f) { + this.fconst_1(); + return; + } + if (inlinedValue == 2.0f) { + this.fconst_2(); + return; + } + this.ldc(inlinedValue); +} +public void generateInlinedValue(int inlinedValue) { + switch (inlinedValue) { + case -1 : + this.iconst_m1(); + break; + case 0 : + this.iconst_0(); + break; + case 1 : + this.iconst_1(); + break; + case 2 : + this.iconst_2(); + break; + case 3 : + this.iconst_3(); + break; + case 4 : + this.iconst_4(); + break; + case 5 : + this.iconst_5(); + break; + default : + if ((-128 <= inlinedValue) && (inlinedValue <= 127)) { + this.bipush((byte) inlinedValue); + return; + } + if ((-32768 <= inlinedValue) && (inlinedValue <= 32767)) { + this.sipush(inlinedValue); + return; + } + this.ldc(inlinedValue); + } +} +public void generateInlinedValue(long inlinedValue) { + if (inlinedValue == 0) { + this.lconst_0(); + return; + } + if (inlinedValue == 1) { + this.lconst_1(); + return; + } + this.ldc2_w(inlinedValue); +} +public void generateInlinedValue(short inlinedValue) { + switch (inlinedValue) { + case -1 : + this.iconst_m1(); + break; + case 0 : + this.iconst_0(); + break; + case 1 : + this.iconst_1(); + break; + case 2 : + this.iconst_2(); + break; + case 3 : + this.iconst_3(); + break; + case 4 : + this.iconst_4(); + break; + case 5 : + this.iconst_5(); + break; + default : + if ((-128 <= inlinedValue) && (inlinedValue <= 127)) { + this.bipush((byte) inlinedValue); + return; + } + this.sipush(inlinedValue); + } +} +public void generateInlinedValue(boolean inlinedValue) { + if (inlinedValue) + this.iconst_1(); + else + this.iconst_0(); +} +public void generateOuterAccess(Object[] mappingSequence, AstNode invocationSite, Scope scope) { + if (mappingSequence == null) + return; + if (mappingSequence == BlockScope.EmulationPathToImplicitThis) { + if (scope.methodScope().isConstructorCall){ + scope.problemReporter().errorThisSuperInStatic(invocationSite); + } + this.aload_0(); + return; + } + if (mappingSequence[0] instanceof FieldBinding) { + FieldBinding fieldBinding = (FieldBinding) mappingSequence[0]; + if (scope.methodScope().isConstructorCall){ + scope.problemReporter().errorThisSuperInStatic(invocationSite); + } + this.aload_0(); + this.getfield(fieldBinding); + } else { + load((LocalVariableBinding) mappingSequence[0]); + } + for (int i = 1, length = mappingSequence.length; i < length; i++) { + if (mappingSequence[i] instanceof FieldBinding) { + FieldBinding fieldBinding = (FieldBinding) mappingSequence[i]; + this.getfield(fieldBinding); + } else { + this.invokestatic((MethodBinding) mappingSequence[i]); + } + } +} +/** + * The equivalent code performs a string conversion: + * + * @param oper1 org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param oper1 org.eclipse.jdt.internal.compiler.ast.Expression + * @param oper2 org.eclipse.jdt.internal.compiler.ast.Expression + */ +public void generateStringAppend(BlockScope blockScope, Expression oper1, Expression oper2) { + int pc; + if (oper1 == null) { + /* Operand is already on the stack, and maybe nil: + note type1 is always to java.lang.String here.*/ + this.newStringBuffer(); + this.dup_x1(); + this.swap(); + // If argument is reference type, need to transform it + // into a string (handles null case) + this.invokeStringValueOf(T_Object); + this.invokeStringBufferStringConstructor(); + } else { + pc = position; + oper1.generateOptimizedStringBufferCreation(blockScope, this, oper1.implicitConversion & 0xF); + this.recordPositionsFrom(pc, oper1.sourceStart); + } + pc = position; + oper2.generateOptimizedStringBuffer(blockScope, this, oper2.implicitConversion & 0xF); + this.recordPositionsFrom(pc, oper2.sourceStart); + this.invokeStringBufferToString(); +} +/** + * Code responsible to generate the suitable code to supply values for the synthetic arguments of + * a constructor invocation of a nested type. + */ +public void generateSyntheticArgumentValues(BlockScope currentScope, ReferenceBinding targetType, Expression enclosingInstance, AstNode invocationSite) { + + // perform some emulation work in case there is some and we are inside a local type only + ReferenceBinding[] syntheticArgumentTypes; + + // generate the enclosing instance first + if ((syntheticArgumentTypes = targetType.syntheticEnclosingInstanceTypes()) != null) { + + ReferenceBinding targetEnclosingType = targetType.isAnonymousType() ? + targetType.superclass().enclosingType() // supplying enclosing instance for the anonymous type's superclass + : targetType.enclosingType(); + + for (int i = 0, max = syntheticArgumentTypes.length; i < max; i++) { + ReferenceBinding syntheticArgType = syntheticArgumentTypes[i]; + if (enclosingInstance != null && i == 0) { + if (syntheticArgType != targetEnclosingType) { + currentScope.problemReporter().unnecessaryEnclosingInstanceSpecification(enclosingInstance, targetType); + } + //if (currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4){ + enclosingInstance.generateCode(currentScope, this, true); + if (syntheticArgType == targetEnclosingType){ + this.dup(); + } + this.invokeObjectGetClass(); // causes null check for all explicit enclosing instances + this.pop(); + //} else { + // enclosingInstance.generateCode(currentScope, this, syntheticArgType == targetEnclosingType); + //} + } else { + Object[] emulationPath = currentScope.getCompatibleEmulationPath(syntheticArgType); + if (emulationPath == null) { + currentScope.problemReporter().missingEnclosingInstanceSpecification(syntheticArgType, invocationSite); + } else { + this.generateOuterAccess(emulationPath, invocationSite, currentScope); + } + } + } + } else { // we may still have an enclosing instance to consider + if (enclosingInstance != null) { + currentScope.problemReporter().unnecessaryEnclosingInstanceSpecification(enclosingInstance, targetType); + //if (currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4){ + enclosingInstance.generateCode(currentScope, this, true); + this.invokeObjectGetClass(); // causes null check for all explicit enclosing instances + this.pop(); + //} else { + // enclosingInstance.generateCode(currentScope, this, false); // do not want the value + //} + } + } + // generate the synthetic outer arguments then + SyntheticArgumentBinding syntheticArguments[]; + if ((syntheticArguments = targetType.syntheticOuterLocalVariables()) != null) { + for (int i = 0, max = syntheticArguments.length; i < max; i++) { + VariableBinding[] emulationPath = currentScope.getEmulationPath(syntheticArguments[i].actualOuterLocalVariable); + if (emulationPath == null) { + // could not emulate a path to a given outer local variable (internal error) + currentScope.problemReporter().needImplementation(); + } else { + this.generateOuterAccess(emulationPath, invocationSite, currentScope); + } + } + } +} +/** + * @param parameters org.eclipse.jdt.internal.compiler.lookup.TypeBinding[] + * @param constructorBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding + */ +public void generateSyntheticBodyForConstructorAccess(SyntheticAccessMethodBinding accessBinding) { + + initializeMaxLocals(accessBinding); + + MethodBinding constructorBinding = accessBinding.targetMethod; + TypeBinding[] parameters = constructorBinding.parameters; + int length = parameters.length; + int resolvedPosition = 1; + this.aload_0(); + if (constructorBinding.declaringClass.isNestedType()) { + NestedTypeBinding nestedType = (NestedTypeBinding) constructorBinding.declaringClass; + SyntheticArgumentBinding[] syntheticArguments = nestedType.syntheticEnclosingInstances(); + for (int i = 0; i < (syntheticArguments == null ? 0 : syntheticArguments.length); i++) { + TypeBinding type; + load((type = syntheticArguments[i].type), resolvedPosition); + if ((type == DoubleBinding) || (type == LongBinding)) + resolvedPosition += 2; + else + resolvedPosition++; + } + syntheticArguments = nestedType.syntheticOuterLocalVariables(); + for (int i = 0; i < (syntheticArguments == null ? 0 : syntheticArguments.length); i++) { + TypeBinding type; + load((type = syntheticArguments[i].type), resolvedPosition); + if ((type == DoubleBinding) || (type == LongBinding)) + resolvedPosition += 2; + else + resolvedPosition++; + } + } + for (int i = 0; i < length; i++) { + load(parameters[i], resolvedPosition); + if ((parameters[i] == DoubleBinding) || (parameters[i] == LongBinding)) + resolvedPosition += 2; + else + resolvedPosition++; + } + this.invokespecial(constructorBinding); + this.return_(); +} +public void generateSyntheticBodyForFieldReadAccess(SyntheticAccessMethodBinding accessBinding) { + initializeMaxLocals(accessBinding); + FieldBinding fieldBinding = accessBinding.targetReadField; + TypeBinding type; + if (fieldBinding.isStatic()) + this.getstatic(fieldBinding); + else { + this.aload_0(); + this.getfield(fieldBinding); + } + if ((type = fieldBinding.type).isBaseType()) { + if (type == IntBinding) + this.ireturn(); + else + if (type == FloatBinding) + this.freturn(); + else + if (type == LongBinding) + this.lreturn(); + else + if (type == DoubleBinding) + this.dreturn(); + else + this.ireturn(); + } else + this.areturn(); +} +public void generateSyntheticBodyForFieldWriteAccess(SyntheticAccessMethodBinding accessBinding) { + initializeMaxLocals(accessBinding); + FieldBinding fieldBinding = accessBinding.targetWriteField; + if (fieldBinding.isStatic()) { + load(fieldBinding.type, 0); + this.putstatic(fieldBinding); + } else { + this.aload_0(); + load(fieldBinding.type, 1); + this.putfield(fieldBinding); + } + this.return_(); +} +public void generateSyntheticBodyForMethodAccess(SyntheticAccessMethodBinding accessBinding) { + + initializeMaxLocals(accessBinding); + MethodBinding methodBinding = accessBinding.targetMethod; + TypeBinding[] parameters = methodBinding.parameters; + int length = parameters.length; + int resolvedPosition; + if (methodBinding.isStatic()) + resolvedPosition = 0; + else { + this.aload_0(); + resolvedPosition = 1; + } + for (int i = 0; i < length; i++) { + load(parameters[i], resolvedPosition); + if ((parameters[i] == DoubleBinding) || (parameters[i] == LongBinding)) + resolvedPosition += 2; + else + resolvedPosition++; + } + TypeBinding type; + if (methodBinding.isStatic()) + this.invokestatic(methodBinding); + else { + if (methodBinding.isConstructor() + || methodBinding.isPrivate() + // qualified super "X.super.foo()" targets methods from superclass + || (methodBinding.declaringClass != methodDeclaration.binding.declaringClass)){ + this.invokespecial(methodBinding); + } else { + if (methodBinding.declaringClass.isInterface()){ + this.invokeinterface(methodBinding); + } else { + this.invokevirtual(methodBinding); + } + } + } + if ((type = methodBinding.returnType).isBaseType()) + if (type == VoidBinding) + this.return_(); + else + if (type == IntBinding) + this.ireturn(); + else + if (type == FloatBinding) + this.freturn(); + else + if (type == LongBinding) + this.lreturn(); + else + if (type == DoubleBinding) + this.dreturn(); + else + this.ireturn(); + else + this.areturn(); +} +final public byte[] getContents() { + byte[] contents; + System.arraycopy(bCodeStream, 0, contents = new byte[position], 0, position); + return contents; +} +final public void getfield(FieldBinding fieldBinding) { + countLabels = 0; + if ((fieldBinding.type.id == T_double) || (fieldBinding.type.id == T_long)) { + if (++stackDepth > stackMax) + stackMax = stackDepth; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_getfield; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_getfield); + } + writeUnsignedShort(constantPool.literalIndex(fieldBinding)); +} +final public void getstatic(FieldBinding fieldBinding) { + countLabels = 0; + if ((fieldBinding.type.id == T_double) || (fieldBinding.type.id == T_long)) + stackDepth += 2; + else + stackDepth += 1; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_getstatic; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_getstatic); + } + writeUnsignedShort(constantPool.literalIndex(fieldBinding)); +} +public void getSystemOut() { + countLabels = 0; + if (++stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_getstatic; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_getstatic); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangSystemOut()); +} +public void getTYPE(int baseTypeID) { + countLabels = 0; + if (++stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_getstatic; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_getstatic); + } + switch (baseTypeID) { + // getstatic: java.lang.Byte.TYPE + case T_byte : + writeUnsignedShort(constantPool.literalIndexForJavaLangByteTYPE()); + break; + // getstatic: java.lang.Short.TYPE + case T_short : + writeUnsignedShort(constantPool.literalIndexForJavaLangShortTYPE()); + break; + // getstatic: java.lang.Character.TYPE + case T_char : + writeUnsignedShort(constantPool.literalIndexForJavaLangCharacterTYPE()); + break; + // getstatic: java.lang.Integer.TYPE + case T_int : + writeUnsignedShort(constantPool.literalIndexForJavaLangIntegerTYPE()); + break; + // getstatic: java.lang.Long.TYPE + case T_long : + writeUnsignedShort(constantPool.literalIndexForJavaLangLongTYPE()); + break; + // getstatic: java.lang.Float.TYPE + case T_float : + writeUnsignedShort(constantPool.literalIndexForJavaLangFloatTYPE()); + break; + // getstatic: java.lang.Double.TYPE + case T_double : + writeUnsignedShort(constantPool.literalIndexForJavaLangDoubleTYPE()); + break; + // getstatic: java.lang.Boolean.TYPE + case T_boolean : + writeUnsignedShort(constantPool.literalIndexForJavaLangBooleanTYPE()); + break; + // getstatic: java.lang.Void.TYPE + case T_void : + writeUnsignedShort(constantPool.literalIndexForJavaLangVoidTYPE()); + break; + } +} +/** + * We didn't call it goto, because there is a conflit with the goto keyword + */ +final public void goto_(Label lbl) { + if (this.wideMode) { + this.goto_w(lbl); + return; + } + try { + lbl.inlineForwardReferencesFromLabelsTargeting(position); + /* + Possible optimization for code such as: + public Object foo() { + boolean b = true; + if (b) { + if (b) + return null; + } else { + if (b) { + return null; + } + } + return null; + } + The goto around the else block for the first if will + be unreachable, because the thenClause of the second if + returns. + See inlineForwardReferencesFromLabelsTargeting defined + on the Label class for the remaining part of this + optimization. + if (!lbl.isBranchTarget(position)) { + switch(bCodeStream[classFileOffset-1]) { + case OPC_return : + case OPC_areturn: + return; + } + }*/ + position++; + bCodeStream[classFileOffset++] = OPC_goto; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_goto); + } + lbl.branch(); +} + +/** + * We didn't call it goto, because there is a conflit with the goto keyword + */ +final public void internal_goto_(Label lbl) { + try { + lbl.inlineForwardReferencesFromLabelsTargeting(position); + /* + Possible optimization for code such as: + public Object foo() { + boolean b = true; + if (b) { + if (b) + return null; + } else { + if (b) { + return null; + } + } + return null; + } + The goto around the else block for the first if will + be unreachable, because the thenClause of the second if + returns. + See inlineForwardReferencesFromLabelsTargeting defined + on the Label class for the remaining part of this + optimization. + if (!lbl.isBranchTarget(position)) { + switch(bCodeStream[classFileOffset-1]) { + case OPC_return : + case OPC_areturn: + return; + } + }*/ + position++; + bCodeStream[classFileOffset++] = OPC_goto; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_goto); + } + lbl.branch(); +} +final public void goto_w(Label lbl) { + try { + position++; + bCodeStream[classFileOffset++] = OPC_goto_w; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_goto_w); + } + lbl.branchWide(); +} +final public void i2b() { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_i2b; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_i2b); + } +} +final public void i2c() { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_i2c; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_i2c); + } +} +final public void i2d() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_i2d; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_i2d); + } +} +final public void i2f() { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_i2f; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_i2f); + } +} +final public void i2l() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_i2l; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_i2l); + } +} +final public void i2s() { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_i2s; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_i2s); + } +} +final public void iadd() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_iadd; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iadd); + } +} +final public void iaload() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_iaload; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iaload); + } +} +final public void iand() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_iand; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iand); + } +} +final public void iastore() { + countLabels = 0; + stackDepth -= 3; + try { + position++; + bCodeStream[classFileOffset++] = OPC_iastore; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iastore); + } +} +final public void iconst_0() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_iconst_0; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iconst_0); + } +} +final public void iconst_1() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_iconst_1; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iconst_1); + } +} +final public void iconst_2() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_iconst_2; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iconst_2); + } +} +final public void iconst_3() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_iconst_3; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iconst_3); + } +} +final public void iconst_4() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_iconst_4; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iconst_4); + } +} +final public void iconst_5() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_iconst_5; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iconst_5); + } +} +final public void iconst_m1() { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_iconst_m1; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iconst_m1); + } +} +final public void idiv() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_idiv; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_idiv); + } +} +final public void if_acmpeq(Label lbl) { + countLabels = 0; + stackDepth-=2; + if (this.wideMode) { + generateWideConditionalBranch(OPC_if_acmpeq, lbl); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_if_acmpeq; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_if_acmpeq); + } + lbl.branch(); + } +} +final public void if_acmpne(Label lbl) { + countLabels = 0; + stackDepth-=2; + if (this.wideMode) { + generateWideConditionalBranch(OPC_if_acmpne, lbl); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_if_acmpne; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_if_acmpne); + } + lbl.branch(); + } +} +final public void if_icmpeq(Label lbl) { + countLabels = 0; + stackDepth -= 2; + if (this.wideMode) { + generateWideConditionalBranch(OPC_if_icmpeq, lbl); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_if_icmpeq; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_if_icmpeq); + } + lbl.branch(); + } +} +final public void if_icmpge(Label lbl) { + countLabels = 0; + stackDepth -= 2; + if (this.wideMode) { + generateWideConditionalBranch(OPC_if_icmpge, lbl); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_if_icmpge; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_if_icmpge); + } + lbl.branch(); + } +} +final public void if_icmpgt(Label lbl) { + countLabels = 0; + stackDepth -= 2; + if (this.wideMode) { + generateWideConditionalBranch(OPC_if_icmpgt, lbl); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_if_icmpgt; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_if_icmpgt); + } + lbl.branch(); + } +} +final public void if_icmple(Label lbl) { + countLabels = 0; + stackDepth -= 2; + if (this.wideMode) { + generateWideConditionalBranch(OPC_if_icmple, lbl); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_if_icmple; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_if_icmple); + } + lbl.branch(); + } +} +final public void if_icmplt(Label lbl) { + countLabels = 0; + stackDepth -= 2; + if (this.wideMode) { + generateWideConditionalBranch(OPC_if_icmplt, lbl); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_if_icmplt; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_if_icmplt); + } + lbl.branch(); + } +} +final public void if_icmpne(Label lbl) { + countLabels = 0; + stackDepth -= 2; + if (this.wideMode) { + generateWideConditionalBranch(OPC_if_icmpne, lbl); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_if_icmpne; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_if_icmpne); + } + lbl.branch(); + } +} +final public void ifeq(Label lbl) { + countLabels = 0; + stackDepth--; + if (this.wideMode) { + generateWideConditionalBranch(OPC_ifeq, lbl); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_ifeq; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ifeq); + } + lbl.branch(); + } +} +final public void ifge(Label lbl) { + countLabels = 0; + stackDepth--; + if (this.wideMode) { + generateWideConditionalBranch(OPC_ifge, lbl); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_ifge; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ifge); + } + lbl.branch(); + } +} +final public void ifgt(Label lbl) { + countLabels = 0; + stackDepth--; + if (this.wideMode) { + generateWideConditionalBranch(OPC_ifgt, lbl); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_ifgt; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ifgt); + } + lbl.branch(); + } +} +final public void ifle(Label lbl) { + countLabels = 0; + stackDepth--; + if (this.wideMode) { + generateWideConditionalBranch(OPC_ifle, lbl); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_ifle; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ifle); + } + lbl.branch(); + } +} +final public void iflt(Label lbl) { + countLabels = 0; + stackDepth--; + if (this.wideMode) { + generateWideConditionalBranch(OPC_iflt, lbl); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_iflt; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iflt); + } + lbl.branch(); + } +} +final public void ifne(Label lbl) { + countLabels = 0; + stackDepth--; + if (this.wideMode) { + generateWideConditionalBranch(OPC_ifne, lbl); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_ifne; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ifne); + } + lbl.branch(); + } +} +final public void ifnonnull(Label lbl) { + countLabels = 0; + stackDepth--; + if (this.wideMode) { + generateWideConditionalBranch(OPC_ifnonnull, lbl); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_ifnonnull; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ifnonnull); + } + lbl.branch(); + } +} +final public void ifnull(Label lbl) { + countLabels = 0; + stackDepth--; + if (this.wideMode) { + generateWideConditionalBranch(OPC_ifnull, lbl); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_ifnull; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ifnull); + } + lbl.branch(); + } +} +final public void iinc(int index, int value) { + countLabels = 0; + if ((index > 255) || (value < -128 || value > 127)) { // have to widen + try { + position++; + bCodeStream[classFileOffset++] = OPC_wide; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_wide); + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_iinc; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iinc); + } + writeUnsignedShort(index); + writeSignedShort(value); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_iinc; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iinc); + } + writeUnsignedByte(index); + writeSignedByte(value); + } +} +final public void iload(int iArg) { + countLabels = 0; + stackDepth++; + if (maxLocals <= iArg) { + maxLocals = iArg + 1; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + if (iArg > 255) { // Widen + try { + position++; + bCodeStream[classFileOffset++] = OPC_wide; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_wide); + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_iload; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iload); + } + writeUnsignedShort(iArg); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_iload; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iload); + } + try { + position++; + bCodeStream[classFileOffset++] = (byte) iArg; + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) iArg); + } + } +} +final public void iload_0() { + countLabels = 0; + stackDepth++; + if (maxLocals <= 0) { + maxLocals = 1; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_iload_0; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iload_0); + } +} +final public void iload_1() { + countLabels = 0; + stackDepth++; + if (maxLocals <= 1) { + maxLocals = 2; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_iload_1; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iload_1); + } +} +final public void iload_2() { + countLabels = 0; + stackDepth++; + if (maxLocals <= 2) { + maxLocals = 3; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_iload_2; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iload_2); + } +} +final public void iload_3() { + countLabels = 0; + stackDepth++; + if (maxLocals <= 3) { + maxLocals = 4; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_iload_3; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iload_3); + } +} +final public void imul() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_imul; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_imul); + } +} +public void incrementTemp(LocalVariableBinding localBinding, int value) { + if (value == (short) value) { + this.iinc(localBinding.resolvedPosition, value); + return; + } + load(localBinding); + this.ldc(value); + this.iadd(); + store(localBinding, false); +} +public void incrStackSize(int offset) { + if ((stackDepth += offset) > stackMax) + stackMax = stackDepth; +} +public int indexOfSameLineEntrySincePC(int pc, int line) { + for (int index = pc, max = pcToSourceMapSize; index < max; index+=2) { + if (pcToSourceMap[index+1] == line) + return index; + } + return -1; +} +final public void ineg() { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_ineg; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ineg); + } +} +public void init(ClassFile classFile) { + this.classFile = classFile; + this.constantPool = classFile.constantPool; + this.bCodeStream = classFile.contents; + this.classFileOffset = classFile.contentsOffset; + this.startingClassFileOffset = this.classFileOffset; + pcToSourceMapSize = 0; + lastEntryPC = 0; + int length = visibleLocals.length; + if (noVisibleLocals.length < length) { + noVisibleLocals = new LocalVariableBinding[length]; + } + System.arraycopy(noVisibleLocals, 0, visibleLocals, 0, length); + visibleLocalsCount = 0; + + length = locals.length; + if (noLocals.length < length) { + noLocals = new LocalVariableBinding[length]; + } + System.arraycopy(noLocals, 0, locals, 0, length); + allLocalsCounter = 0; + + length = exceptionHandlers.length; + if (noExceptionHandlers.length < length) { + noExceptionHandlers = new ExceptionLabel[length]; + } + System.arraycopy(noExceptionHandlers, 0, exceptionHandlers, 0, length); + exceptionHandlersNumber = 0; + + length = labels.length; + if (noLabels.length < length) { + noLabels = new Label[length]; + } + System.arraycopy(noLabels, 0, labels, 0, length); + countLabels = 0; + + stackMax = 0; + stackDepth = 0; + maxLocals = 0; + position = 0; +} +/** + * @param methodDeclaration org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration + * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile + */ +public void initializeMaxLocals(MethodBinding methodBinding) { + + maxLocals = (methodBinding == null || methodBinding.isStatic()) ? 0 : 1; + // take into account the synthetic parameters + if (methodBinding != null) { + if (methodBinding.isConstructor() && methodBinding.declaringClass.isNestedType()) { + ReferenceBinding enclosingInstanceTypes[]; + if ((enclosingInstanceTypes = methodBinding.declaringClass.syntheticEnclosingInstanceTypes()) != null) { + for (int i = 0, max = enclosingInstanceTypes.length; i < max; i++) { + maxLocals++; // an enclosingInstanceType can only be a reference binding. It cannot be + // LongBinding or DoubleBinding + } + } + SyntheticArgumentBinding syntheticArguments[]; + if ((syntheticArguments = methodBinding.declaringClass.syntheticOuterLocalVariables()) != null) { + for (int i = 0, max = syntheticArguments.length; i < max; i++) { + TypeBinding argType; + if (((argType = syntheticArguments[i].type) == LongBinding) || (argType == DoubleBinding)) { + maxLocals += 2; + } else { + maxLocals++; + } + } + } + } + TypeBinding[] arguments; + if ((arguments = methodBinding.parameters) != null) { + for (int i = 0, max = arguments.length; i < max; i++) { + TypeBinding argType; + if (((argType = arguments[i]) == LongBinding) || (argType == DoubleBinding)) { + maxLocals += 2; + } else { + maxLocals++; + } + } + } + } +} +/** + * This methods searches for an existing entry inside the pcToSourceMap table with a pc equals to @pc. + * If there is an existing entry it returns -1 (no insertion required). + * Otherwise it returns the index where the entry for the pc has to be inserted. + * This is based on the fact that the pcToSourceMap table is sorted according to the pc. + * + * @param int pc + * @return int + */ +public static int insertionIndex(int[] pcToSourceMap, int length, int pc) { + int g = 0; + int d = length - 2; + int m = 0; + while (g <= d) { + m = (g + d) / 2; + // we search only on even indexes + if ((m % 2) != 0) + m--; + int currentPC = pcToSourceMap[m]; + if (pc < currentPC) { + d = m - 2; + } else + if (pc > currentPC) { + g = m + 2; + } else { + return -1; + } + } + if (pc < pcToSourceMap[m]) + return m; + return m + 2; +} +/** + * We didn't call it instanceof because there is a conflit with the + * instanceof keyword + */ +final public void instance_of(TypeBinding typeBinding) { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_instanceof; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_instanceof); + } + writeUnsignedShort(constantPool.literalIndex(typeBinding)); +} +public void invokeClassForName() { + // invokestatic: java.lang.Class.forName(Ljava.lang.String;)Ljava.lang.Class; + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokestatic; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokestatic); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangClassForName()); +} + +public void invokeJavaLangClassDesiredAssertionStatus() { + // invokevirtual: java.lang.Class.desiredAssertionStatus()Z; + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokevirtual; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokevirtual); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangClassDesiredAssertionStatus()); +} + +public void invokeConstructorGetConstructor() { + // invokevirtual: java.lang.Class.getConstructor(java.lang.Class[])Ljava.lang.reflect.Constructor; + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokevirtual; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokevirtual); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangClassGetConstructor()); +} +final public void invokeinterface(MethodBinding methodBinding) { + // initialized to 1 to take into account this immediately + countLabels = 0; + int argCount = 1; + int id; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokeinterface; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokeinterface); + } + writeUnsignedShort(constantPool.literalIndex(methodBinding)); + for (int i = methodBinding.parameters.length - 1; i >= 0; i--) + if (((id = methodBinding.parameters[i].id) == T_double) || (id == T_long)) + argCount += 2; + else + argCount += 1; + writeUnsignedByte(argCount); + // Generate a 0 into the byte array. Like the array is already fill with 0, we just need to increment + // the number of bytes. + position++; + classFileOffset++; + if (((id = methodBinding.returnType.id) == T_double) || (id == T_long)) + stackDepth += (2 - argCount); + else + if (id == T_void) + stackDepth -= argCount; + else + stackDepth += (1 - argCount); + if (stackDepth > stackMax) + stackMax = stackDepth; +} +public void invokeJavaLangErrorConstructor() { + // invokespecial: java.lang.Error(Ljava.lang.String;)V + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokespecial; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokespecial); + } + stackDepth -= 2; + writeUnsignedShort(constantPool.literalIndexForJavaLangErrorConstructor()); +} +public void invokeNoClassDefFoundErrorStringConstructor() { + // invokespecial: java.lang.NoClassDefFoundError.(Ljava.lang.String;)V + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokespecial; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokespecial); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangNoClassDefFoundErrorStringConstructor()); + stackDepth -= 2; +} +public void invokeObjectNewInstance() { + // invokevirtual: java.lang.reflect.Constructor.newInstance(java.lang.Object[])Ljava.lang.Object; + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokevirtual; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokevirtual); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangReflectConstructorNewInstance()); +} + +public void invokeObjectGetClass() { + // invokevirtual: java.lang.Object.getClass()Ljava.lang.Class; + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokevirtual; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokevirtual); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangObjectGetClass()); +} + +final public void invokespecial(MethodBinding methodBinding) { + // initialized to 1 to take into account this immediately + countLabels = 0; + int argCount = 1; + int id; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokespecial; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokespecial); + } + writeUnsignedShort(constantPool.literalIndex(methodBinding)); + if (methodBinding.isConstructor() && methodBinding.declaringClass.isNestedType()) { + // enclosing instances + TypeBinding[] syntheticArgumentTypes = methodBinding.declaringClass.syntheticEnclosingInstanceTypes(); + if (syntheticArgumentTypes != null) { + for (int i = 0, max = syntheticArgumentTypes.length; i < max; i++) { + if (((id = syntheticArgumentTypes[i].id) == T_double) || (id == T_long)) { + argCount += 2; + } else { + argCount++; + } + } + } + // outer local variables + SyntheticArgumentBinding[] syntheticArguments = methodBinding.declaringClass.syntheticOuterLocalVariables(); + if (syntheticArguments != null) { + for (int i = 0, max = syntheticArguments.length; i < max; i++) { + if (((id = syntheticArguments[i].type.id) == T_double) || (id == T_long)) { + argCount += 2; + } else { + argCount++; + } + } + } + } + for (int i = methodBinding.parameters.length - 1; i >= 0; i--) + if (((id = methodBinding.parameters[i].id) == T_double) || (id == T_long)) + argCount += 2; + else + argCount++; + if (((id = methodBinding.returnType.id) == T_double) || (id == T_long)) + stackDepth += (2 - argCount); + else + if (id == T_void) + stackDepth -= argCount; + else + stackDepth += (1 - argCount); + if (stackDepth > stackMax) + stackMax = stackDepth; +} +final public void invokestatic(MethodBinding methodBinding) { + // initialized to 0 to take into account that there is no this for + // a static method + countLabels = 0; + int argCount = 0; + int id; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokestatic; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokestatic); + } + writeUnsignedShort(constantPool.literalIndex(methodBinding)); + for (int i = methodBinding.parameters.length - 1; i >= 0; i--) + if (((id = methodBinding.parameters[i].id) == T_double) || (id == T_long)) + argCount += 2; + else + argCount += 1; + if (((id = methodBinding.returnType.id) == T_double) || (id == T_long)) + stackDepth += (2 - argCount); + else + if (id == T_void) + stackDepth -= argCount; + else + stackDepth += (1 - argCount); + if (stackDepth > stackMax) + stackMax = stackDepth; +} +/** + * The equivalent code performs a string conversion of the TOS + * @param typeID int + */ +public void invokeStringBufferAppendForType(int typeID) { + countLabels = 0; + int usedTypeID; + if (typeID == T_null) + usedTypeID = T_String; + else + usedTypeID = typeID; + // invokevirtual + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokevirtual; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokevirtual); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangStringBufferAppend(typeID)); + if ((usedTypeID == T_long) || (usedTypeID == T_double)) + stackDepth -= 2; + else + stackDepth--; +} + +public void invokeJavaLangAssertionErrorConstructor(int typeBindingID) { + // invokespecial: java.lang.AssertionError.(typeBindingID)V + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokespecial; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokespecial); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangAssertionErrorConstructor(typeBindingID)); + stackDepth -= 2; +} + +public void invokeJavaLangAssertionErrorDefaultConstructor() { + // invokespecial: java.lang.AssertionError.()V + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokespecial; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokespecial); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangAssertionErrorDefaultConstructor()); + stackDepth --; +} + +public void invokeStringBufferDefaultConstructor() { + // invokespecial: java.lang.StringBuffer.()V + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokespecial; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokespecial); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangStringBufferDefaultConstructor()); + stackDepth--; +} +public void invokeStringBufferStringConstructor() { + // invokespecial: java.lang.StringBuffer.(Ljava.lang.String;)V + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokespecial; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokespecial); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangStringBufferConstructor()); + stackDepth -= 2; +} + +public void invokeStringBufferToString() { + // invokevirtual: StringBuffer.toString()Ljava.lang.String; + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokevirtual; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokevirtual); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangStringBufferToString()); +} +public void invokeStringIntern() { + // invokevirtual: java.lang.String.intern() + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokevirtual; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokevirtual); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangStringIntern()); +} +public void invokeStringValueOf(int typeID) { + // invokestatic: java.lang.String.valueOf(argumentType) + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokestatic; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokestatic); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangStringValueOf(typeID)); +} +public void invokeSystemExit() { + // invokestatic: java.lang.System.exit(I) + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokestatic; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokestatic); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangSystemExitInt()); + stackDepth--; // int argument +} +public void invokeThrowableGetMessage() { + // invokevirtual: java.lang.Throwable.getMessage()Ljava.lang.String; + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokevirtual; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokevirtual); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangThrowableGetMessage()); +} +final public void invokevirtual(MethodBinding methodBinding) { + // initialized to 1 to take into account this immediately + countLabels = 0; + int argCount = 1; + int id; + try { + position++; + bCodeStream[classFileOffset++] = OPC_invokevirtual; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_invokevirtual); + } + writeUnsignedShort(constantPool.literalIndex(methodBinding)); + for (int i = methodBinding.parameters.length - 1; i >= 0; i--) + if (((id = methodBinding.parameters[i].id) == T_double) || (id == T_long)) + argCount += 2; + else + argCount++; + if (((id = methodBinding.returnType.id) == T_double) || (id == T_long)) + stackDepth += (2 - argCount); + else + if (id == T_void) + stackDepth -= argCount; + else + stackDepth += (1 - argCount); + if (stackDepth > stackMax) + stackMax = stackDepth; +} +final public void ior() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_ior; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ior); + } +} +final public void irem() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_irem; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_irem); + } +} +final public void ireturn() { + countLabels = 0; + stackDepth--; + // the stackDepth should be equal to 0 + try { + position++; + bCodeStream[classFileOffset++] = OPC_ireturn; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ireturn); + } +} +public boolean isDefinitelyAssigned(Scope scope, int initStateIndex, LocalVariableBinding local) { + // Dependant of UnconditionalFlowInfo.isDefinitelyAssigned(..) + if (initStateIndex == -1) + return false; + if (local.isArgument) { + return true; + } + int position = local.id + maxFieldCount; + MethodScope methodScope = scope.methodScope(); + // id is zero-based + if (position < UnconditionalFlowInfo.BitCacheSize) { + return (methodScope.definiteInits[initStateIndex] & (1L << position)) != 0; // use bits + } + // use extra vector + long[] extraInits = methodScope.extraDefiniteInits[initStateIndex]; + if (extraInits == null) + return false; // if vector not yet allocated, then not initialized + int vectorIndex; + if ((vectorIndex = (position / UnconditionalFlowInfo.BitCacheSize) - 1) >= extraInits.length) + return false; // if not enough room in vector, then not initialized + return ((extraInits[vectorIndex]) & (1L << (position % UnconditionalFlowInfo.BitCacheSize))) != 0; +} +final public void ishl() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_ishl; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ishl); + } +} +final public void ishr() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_ishr; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ishr); + } +} +final public void istore(int iArg) { + countLabels = 0; + stackDepth--; + if (maxLocals <= iArg) { + maxLocals = iArg + 1; + } + if (iArg > 255) { // Widen + try { + position++; + bCodeStream[classFileOffset++] = OPC_wide; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_wide); + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_istore; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_istore); + } + writeUnsignedShort(iArg); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_istore; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_istore); + } + try { + position++; + bCodeStream[classFileOffset++] = (byte) iArg; + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) iArg); + } + } +} +final public void istore_0() { + countLabels = 0; + stackDepth--; + if (maxLocals == 0) { + maxLocals = 1; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_istore_0; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_istore_0); + } +} +final public void istore_1() { + countLabels = 0; + stackDepth--; + if (maxLocals <= 1) { + maxLocals = 2; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_istore_1; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_istore_1); + } +} +final public void istore_2() { + countLabels = 0; + stackDepth--; + if (maxLocals <= 2) { + maxLocals = 3; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_istore_2; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_istore_2); + } +} +final public void istore_3() { + countLabels = 0; + stackDepth--; + if (maxLocals <= 3) { + maxLocals = 4; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_istore_3; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_istore_3); + } +} +final public void isub() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_isub; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_isub); + } +} +final public void iushr() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_iushr; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_iushr); + } +} +final public void ixor() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_ixor; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ixor); + } +} +final public void jsr(Label lbl) { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_jsr; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_jsr); + } + lbl.branch(); +} +final public void jsr_w(Label lbl) { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_jsr_w; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_jsr_w); + } + lbl.branchWide(); +} +final public void l2d() { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_l2d; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_l2d); + } +} +final public void l2f() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_l2f; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_l2f); + } +} +final public void l2i() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_l2i; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_l2i); + } +} +final public void ladd() { + countLabels = 0; + stackDepth -= 2; + try { + position++; + bCodeStream[classFileOffset++] = OPC_ladd; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ladd); + } +} +final public void laload() { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_laload; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_laload); + } +} +final public void land() { + countLabels = 0; + stackDepth -= 2; + try { + position++; + bCodeStream[classFileOffset++] = OPC_land; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_land); + } +} +final public void lastore() { + countLabels = 0; + stackDepth -= 4; + try { + position++; + bCodeStream[classFileOffset++] = OPC_lastore; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lastore); + } +} +final public void lcmp() { + countLabels = 0; + stackDepth -= 3; + try { + position++; + bCodeStream[classFileOffset++] = OPC_lcmp; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lcmp); + } +} +final public void lconst_0() { + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_lconst_0; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lconst_0); + } +} +final public void lconst_1() { + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_lconst_1; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lconst_1); + } +} +final public void ldc(float constant) { + countLabels = 0; + int index = constantPool.literalIndex(constant); + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (index > 255) { + // Generate a ldc_w + try { + position++; + bCodeStream[classFileOffset++] = OPC_ldc_w; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ldc_w); + } + writeUnsignedShort(index); + } else { + // Generate a ldc + try { + position++; + bCodeStream[classFileOffset++] = OPC_ldc; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ldc); + } + writeUnsignedByte(index); + } +} +final public void ldc(int constant) { + countLabels = 0; + int index = constantPool.literalIndex(constant); + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (index > 255) { + // Generate a ldc_w + try { + position++; + bCodeStream[classFileOffset++] = OPC_ldc_w; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ldc_w); + } + writeUnsignedShort(index); + } else { + // Generate a ldc + try { + position++; + bCodeStream[classFileOffset++] = OPC_ldc; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ldc); + } + writeUnsignedByte(index); + } +} +final public void ldc(String constant) { + countLabels = 0; + int currentConstantPoolIndex = constantPool.currentIndex; + int currentConstantPoolOffset = constantPool.currentOffset; + int currentCodeStreamPosition = position; + int index = constantPool.literalIndexForLdc(constant.toCharArray()); + if (index > 0) { + // the string already exists inside the constant pool + // we reuse the same index + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (index > 255) { + // Generate a ldc_w + try { + position++; + bCodeStream[classFileOffset++] = OPC_ldc_w; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ldc_w); + } + writeUnsignedShort(index); + } else { + // Generate a ldc + try { + position++; + bCodeStream[classFileOffset++] = OPC_ldc; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ldc); + } + writeUnsignedByte(index); + } + } else { + // the string is too big to be utf8-encoded in one pass. + // we have to split it into different pieces. + // first we clean all side-effects due to the code above + // this case is very rare, so we can afford to lose time to handle it + char[] constantChars = constant.toCharArray(); + position = currentCodeStreamPosition; + constantPool.currentIndex = currentConstantPoolIndex; + constantPool.currentOffset = currentConstantPoolOffset; + constantPool.stringCache.remove(constantChars); + constantPool.UTF8Cache.remove(constantChars); + int i = 0; + int length = 0; + int constantLength = constant.length(); + byte[] utf8encoding = new byte[Math.min(constantLength + 100, 65535)]; + int utf8encodingLength = 0; + while ((length < 65532) && (i < constantLength)) { + char current = constantChars[i]; + // we resize the byte array immediately if necessary + if (length + 3 > (utf8encodingLength = utf8encoding.length)) { + System.arraycopy(utf8encoding, 0, (utf8encoding = new byte[Math.min(utf8encodingLength + 100, 65535)]), 0, length); + } + if ((current >= 0x0001) && (current <= 0x007F)) { + // we only need one byte: ASCII table + utf8encoding[length++] = (byte) current; + } else { + if (current > 0x07FF) { + // we need 3 bytes + utf8encoding[length++] = (byte) (0xE0 | ((current >> 12) & 0x0F)); // 0xE0 = 1110 0000 + utf8encoding[length++] = (byte) (0x80 | ((current >> 6) & 0x3F)); // 0x80 = 1000 0000 + utf8encoding[length++] = (byte) (0x80 | (current & 0x3F)); // 0x80 = 1000 0000 + } else { + // we can be 0 or between 0x0080 and 0x07FF + // In that case we only need 2 bytes + utf8encoding[length++] = (byte) (0xC0 | ((current >> 6) & 0x1F)); // 0xC0 = 1100 0000 + utf8encoding[length++] = (byte) (0x80 | (current & 0x3F)); // 0x80 = 1000 0000 + } + } + i++; + } + // check if all the string is encoded (PR 1PR2DWJ) + // the string is too big to be encoded in one pass + newStringBuffer(); + dup(); + // write the first part + char[] subChars = new char[i]; + System.arraycopy(constantChars, 0, subChars, 0, i); + System.arraycopy(utf8encoding, 0, (utf8encoding = new byte[length]), 0, length); + index = constantPool.literalIndex(subChars, utf8encoding); + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (index > 255) { + // Generate a ldc_w + try { + position++; + bCodeStream[classFileOffset++] = OPC_ldc_w; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ldc_w); + } + writeUnsignedShort(index); + } else { + // Generate a ldc + try { + position++; + bCodeStream[classFileOffset++] = OPC_ldc; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ldc); + } + writeUnsignedByte(index); + } + // write the remaining part + invokeStringBufferStringConstructor(); + while (i < constantLength) { + length = 0; + utf8encoding = new byte[Math.min(constantLength - i + 100, 65535)]; + int startIndex = i; + while ((length < 65532) && (i < constantLength)) { + char current = constantChars[i]; + // we resize the byte array immediately if necessary + if (constantLength + 2 > (utf8encodingLength = utf8encoding.length)) { + System.arraycopy(utf8encoding, 0, (utf8encoding = new byte[Math.min(utf8encodingLength + 100, 65535)]), 0, length); + } + if ((current >= 0x0001) && (current <= 0x007F)) { + // we only need one byte: ASCII table + utf8encoding[length++] = (byte) current; + } else { + if (current > 0x07FF) { + // we need 3 bytes + utf8encoding[length++] = (byte) (0xE0 | ((current >> 12) & 0x0F)); // 0xE0 = 1110 0000 + utf8encoding[length++] = (byte) (0x80 | ((current >> 6) & 0x3F)); // 0x80 = 1000 0000 + utf8encoding[length++] = (byte) (0x80 | (current & 0x3F)); // 0x80 = 1000 0000 + } else { + // we can be 0 or between 0x0080 and 0x07FF + // In that case we only need 2 bytes + utf8encoding[length++] = (byte) (0xC0 | ((current >> 6) & 0x1F)); // 0xC0 = 1100 0000 + utf8encoding[length++] = (byte) (0x80 | (current & 0x3F)); // 0x80 = 1000 0000 + } + } + i++; + } + // the next part is done + subChars = new char[i - startIndex]; + System.arraycopy(constantChars, startIndex, subChars, 0, i - startIndex); + System.arraycopy(utf8encoding, 0, (utf8encoding = new byte[length]), 0, length); + index = constantPool.literalIndex(subChars, utf8encoding); + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (index > 255) { + // Generate a ldc_w + try { + position++; + bCodeStream[classFileOffset++] = OPC_ldc_w; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ldc_w); + } + writeUnsignedShort(index); + } else { + // Generate a ldc + try { + position++; + bCodeStream[classFileOffset++] = OPC_ldc; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ldc); + } + writeUnsignedByte(index); + } + // now on the stack it should be a StringBuffer and a string. + invokeStringBufferAppendForType(T_String); + } + invokeStringBufferToString(); + invokeStringIntern(); + } +} +final public void ldc2_w(double constant) { + countLabels = 0; + int index = constantPool.literalIndex(constant); + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + // Generate a ldc2_w + try { + position++; + bCodeStream[classFileOffset++] = OPC_ldc2_w; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ldc2_w); + } + writeUnsignedShort(index); +} +final public void ldc2_w(long constant) { + countLabels = 0; + int index = constantPool.literalIndex(constant); + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + // Generate a ldc2_w + try { + position++; + bCodeStream[classFileOffset++] = OPC_ldc2_w; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ldc2_w); + } + writeUnsignedShort(index); +} +final public void ldiv() { + countLabels = 0; + stackDepth -= 2; + try { + position++; + bCodeStream[classFileOffset++] = OPC_ldiv; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ldiv); + } +} +final public void lload(int iArg) { + countLabels = 0; + stackDepth += 2; + if (maxLocals <= iArg + 1) { + maxLocals = iArg + 2; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + if (iArg > 255) { // Widen + try { + position++; + bCodeStream[classFileOffset++] = OPC_wide; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_wide); + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_lload; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lload); + } + writeUnsignedShort(iArg); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_lload; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lload); + } + try { + position++; + bCodeStream[classFileOffset++] = (byte) iArg; + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) iArg); + } + } +} +final public void lload_0() { + countLabels = 0; + stackDepth += 2; + if (maxLocals < 2) { + maxLocals = 2; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_lload_0; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lload_0); + } +} +final public void lload_1() { + countLabels = 0; + stackDepth += 2; + if (maxLocals < 3) { + maxLocals = 3; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_lload_1; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lload_1); + } +} +final public void lload_2() { + countLabels = 0; + stackDepth += 2; + if (maxLocals < 4) { + maxLocals = 4; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_lload_2; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lload_2); + } +} +final public void lload_3() { + countLabels = 0; + stackDepth += 2; + if (maxLocals < 5) { + maxLocals = 5; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_lload_3; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lload_3); + } +} +final public void lmul() { + countLabels = 0; + stackDepth -= 2; + try { + position++; + bCodeStream[classFileOffset++] = OPC_lmul; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lmul); + } +} +final public void lneg() { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_lneg; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lneg); + } +} +public final void load(LocalVariableBinding localBinding) { + countLabels = 0; + TypeBinding typeBinding = localBinding.type; + int resolvedPosition = localBinding.resolvedPosition; + // Using dedicated int bytecode + if (typeBinding == IntBinding) { + switch (resolvedPosition) { + case 0 : + this.iload_0(); + break; + case 1 : + this.iload_1(); + break; + case 2 : + this.iload_2(); + break; + case 3 : + this.iload_3(); + break; + default : + this.iload(resolvedPosition); + } + return; + } + // Using dedicated float bytecode + if (typeBinding == FloatBinding) { + switch (resolvedPosition) { + case 0 : + this.fload_0(); + break; + case 1 : + this.fload_1(); + break; + case 2 : + this.fload_2(); + break; + case 3 : + this.fload_3(); + break; + default : + this.fload(resolvedPosition); + } + return; + } + // Using dedicated long bytecode + if (typeBinding == LongBinding) { + switch (resolvedPosition) { + case 0 : + this.lload_0(); + break; + case 1 : + this.lload_1(); + break; + case 2 : + this.lload_2(); + break; + case 3 : + this.lload_3(); + break; + default : + this.lload(resolvedPosition); + } + return; + } + // Using dedicated double bytecode + if (typeBinding == DoubleBinding) { + switch (resolvedPosition) { + case 0 : + this.dload_0(); + break; + case 1 : + this.dload_1(); + break; + case 2 : + this.dload_2(); + break; + case 3 : + this.dload_3(); + break; + default : + this.dload(resolvedPosition); + } + return; + } + // boolean, byte, char and short are handled as int + if ((typeBinding == ByteBinding) || (typeBinding == CharBinding) || (typeBinding == BooleanBinding) || (typeBinding == ShortBinding)) { + switch (resolvedPosition) { + case 0 : + this.iload_0(); + break; + case 1 : + this.iload_1(); + break; + case 2 : + this.iload_2(); + break; + case 3 : + this.iload_3(); + break; + default : + this.iload(resolvedPosition); + } + return; + } + + // Reference object + switch (resolvedPosition) { + case 0 : + this.aload_0(); + break; + case 1 : + this.aload_1(); + break; + case 2 : + this.aload_2(); + break; + case 3 : + this.aload_3(); + break; + default : + this.aload(resolvedPosition); + } +} +public final void load(TypeBinding typeBinding, int resolvedPosition) { + countLabels = 0; + // Using dedicated int bytecode + if (typeBinding == IntBinding) { + switch (resolvedPosition) { + case 0 : + this.iload_0(); + break; + case 1 : + this.iload_1(); + break; + case 2 : + this.iload_2(); + break; + case 3 : + this.iload_3(); + break; + default : + this.iload(resolvedPosition); + } + return; + } + // Using dedicated float bytecode + if (typeBinding == FloatBinding) { + switch (resolvedPosition) { + case 0 : + this.fload_0(); + break; + case 1 : + this.fload_1(); + break; + case 2 : + this.fload_2(); + break; + case 3 : + this.fload_3(); + break; + default : + this.fload(resolvedPosition); + } + return; + } + // Using dedicated long bytecode + if (typeBinding == LongBinding) { + switch (resolvedPosition) { + case 0 : + this.lload_0(); + break; + case 1 : + this.lload_1(); + break; + case 2 : + this.lload_2(); + break; + case 3 : + this.lload_3(); + break; + default : + this.lload(resolvedPosition); + } + return; + } + // Using dedicated double bytecode + if (typeBinding == DoubleBinding) { + switch (resolvedPosition) { + case 0 : + this.dload_0(); + break; + case 1 : + this.dload_1(); + break; + case 2 : + this.dload_2(); + break; + case 3 : + this.dload_3(); + break; + default : + this.dload(resolvedPosition); + } + return; + } + // boolean, byte, char and short are handled as int + if ((typeBinding == ByteBinding) || (typeBinding == CharBinding) || (typeBinding == BooleanBinding) || (typeBinding == ShortBinding)) { + switch (resolvedPosition) { + case 0 : + this.iload_0(); + break; + case 1 : + this.iload_1(); + break; + case 2 : + this.iload_2(); + break; + case 3 : + this.iload_3(); + break; + default : + this.iload(resolvedPosition); + } + return; + } + + // Reference object + switch (resolvedPosition) { + case 0 : + this.aload_0(); + break; + case 1 : + this.aload_1(); + break; + case 2 : + this.aload_2(); + break; + case 3 : + this.aload_3(); + break; + default : + this.aload(resolvedPosition); + } +} +public final void loadInt(int resolvedPosition) { + // Using dedicated int bytecode + switch (resolvedPosition) { + case 0 : + this.iload_0(); + break; + case 1 : + this.iload_1(); + break; + case 2 : + this.iload_2(); + break; + case 3 : + this.iload_3(); + break; + default : + this.iload(resolvedPosition); + } +} +public final void loadObject(int resolvedPosition) { + switch (resolvedPosition) { + case 0 : + this.aload_0(); + break; + case 1 : + this.aload_1(); + break; + case 2 : + this.aload_2(); + break; + case 3 : + this.aload_3(); + break; + default : + this.aload(resolvedPosition); + } +} +final public void lookupswitch(CaseLabel defaultLabel, int[] keys, int[] sortedIndexes, CaseLabel[] casesLabel) { + countLabels = 0; + stackDepth--; + int length = keys.length; + int pos = position; + defaultLabel.placeInstruction(); + for (int i = 0; i < length; i++) { + casesLabel[i].placeInstruction(); + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_lookupswitch; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lookupswitch); + } + for (int i = (3 - (pos % 4)); i > 0; i--) { + position++; // Padding + classFileOffset++; + } + defaultLabel.branch(); + writeSignedWord(length); + for (int i = 0; i < length; i++) { + writeSignedWord(keys[sortedIndexes[i]]); + casesLabel[sortedIndexes[i]].branch(); + } +} +final public void lor() { + countLabels = 0; + stackDepth -= 2; + try { + position++; + bCodeStream[classFileOffset++] = OPC_lor; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lor); + } +} +final public void lrem() { + countLabels = 0; + stackDepth -= 2; + try { + position++; + bCodeStream[classFileOffset++] = OPC_lrem; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lrem); + } +} +final public void lreturn() { + countLabels = 0; + stackDepth -= 2; + // the stackDepth should be equal to 0 + try { + position++; + bCodeStream[classFileOffset++] = OPC_lreturn; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lreturn); + } +} +final public void lshl() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_lshl; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lshl); + } +} +final public void lshr() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_lshr; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lshr); + } +} +final public void lstore(int iArg) { + countLabels = 0; + stackDepth -= 2; + if (maxLocals <= iArg + 1) { + maxLocals = iArg + 2; + } + if (iArg > 255) { // Widen + try { + position++; + bCodeStream[classFileOffset++] = OPC_wide; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_wide); + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_lstore; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lstore); + } + writeUnsignedShort(iArg); + } else { + try { + position++; + bCodeStream[classFileOffset++] = OPC_lstore; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lstore); + } + try { + position++; + bCodeStream[classFileOffset++] = (byte) iArg; + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) iArg); + } + } +} +final public void lstore_0() { + countLabels = 0; + stackDepth -= 2; + if (maxLocals < 2) { + maxLocals = 2; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_lstore_0; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lstore_0); + } +} +final public void lstore_1() { + countLabels = 0; + stackDepth -= 2; + if (maxLocals < 3) { + maxLocals = 3; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_lstore_1; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lstore_1); + } +} +final public void lstore_2() { + countLabels = 0; + stackDepth -= 2; + if (maxLocals < 4) { + maxLocals = 4; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_lstore_2; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lstore_2); + } +} +final public void lstore_3() { + countLabels = 0; + stackDepth -= 2; + if (maxLocals < 5) { + maxLocals = 5; + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_lstore_3; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lstore_3); + } +} +final public void lsub() { + countLabels = 0; + stackDepth -= 2; + try { + position++; + bCodeStream[classFileOffset++] = OPC_lsub; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lsub); + } +} +final public void lushr() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_lushr; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lushr); + } +} +final public void lxor() { + countLabels = 0; + stackDepth -= 2; + try { + position++; + bCodeStream[classFileOffset++] = OPC_lxor; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_lxor); + } +} +final public void monitorenter() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_monitorenter; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_monitorenter); + } +} +final public void monitorexit() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_monitorexit; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_monitorexit); + } +} +final public void multianewarray(TypeBinding typeBinding, int dimensions) { + countLabels = 0; + stackDepth += (1 - dimensions); + try { + position++; + bCodeStream[classFileOffset++] = OPC_multianewarray; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_multianewarray); + } + writeUnsignedShort(constantPool.literalIndex(typeBinding)); + writeUnsignedByte(dimensions); +} +public static void needImplementation() { +} +/** + * We didn't call it new, because there is a conflit with the new keyword + */ +final public void new_(TypeBinding typeBinding) { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_new; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_new); + } + writeUnsignedShort(constantPool.literalIndex(typeBinding)); +} +final public void newarray(int array_Type) { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_newarray; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_newarray); + } + writeUnsignedByte(array_Type); +} +public void newArray(Scope scope, ArrayBinding arrayBinding) { + TypeBinding component = arrayBinding.elementsType(scope); + switch (component.id) { + case T_int : + this.newarray(10); + break; + case T_byte : + this.newarray(8); + break; + case T_boolean : + this.newarray(4); + break; + case T_short : + this.newarray(9); + break; + case T_char : + this.newarray(5); + break; + case T_long : + this.newarray(11); + break; + case T_float : + this.newarray(6); + break; + case T_double : + this.newarray(7); + break; + default : + this.anewarray(component); + } +} +public void newJavaLangError() { + // new: java.lang.Error + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_new; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_new); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangError()); +} + +public void newJavaLangAssertionError() { + // new: java.lang.AssertionError + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_new; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_new); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangAssertionError()); +} + +public void newNoClassDefFoundError() { // new: java.lang.NoClassDefFoundError + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_new; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_new); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangNoClassDefFoundError()); +} +public void newStringBuffer() { // new: java.lang.StringBuffer + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_new; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_new); + } + writeUnsignedShort(constantPool.literalIndexForJavaLangStringBuffer()); +} +public void newWrapperFor(int typeID) { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_new; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_new); + } + switch (typeID) { + case T_int : // new: java.lang.Integer + writeUnsignedShort(constantPool.literalIndexForJavaLangInteger()); + break; + case T_boolean : // new: java.lang.Boolean + writeUnsignedShort(constantPool.literalIndexForJavaLangBoolean()); + break; + case T_byte : // new: java.lang.Byte + writeUnsignedShort(constantPool.literalIndexForJavaLangByte()); + break; + case T_char : // new: java.lang.Character + writeUnsignedShort(constantPool.literalIndexForJavaLangCharacter()); + break; + case T_float : // new: java.lang.Float + writeUnsignedShort(constantPool.literalIndexForJavaLangFloat()); + break; + case T_double : // new: java.lang.Double + writeUnsignedShort(constantPool.literalIndexForJavaLangDouble()); + break; + case T_short : // new: java.lang.Short + writeUnsignedShort(constantPool.literalIndexForJavaLangShort()); + break; + case T_long : // new: java.lang.Long + writeUnsignedShort(constantPool.literalIndexForJavaLangLong()); + break; + case T_void : // new: java.lang.Void + writeUnsignedShort(constantPool.literalIndexForJavaLangVoid()); + } +} +final public void nop() { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_nop; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_nop); + } +} +final public void pop() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_pop; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_pop); + } +} +final public void pop2() { + countLabels = 0; + stackDepth -= 2; + try { + position++; + bCodeStream[classFileOffset++] = OPC_pop2; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_pop2); + } +} +final public void putfield(FieldBinding fieldBinding) { + countLabels = 0; + int id; + if (((id = fieldBinding.type.id) == T_double) || (id == T_long)) + stackDepth -= 3; + else + stackDepth -= 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_putfield; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_putfield); + } + writeUnsignedShort(constantPool.literalIndex(fieldBinding)); +} +final public void putstatic(FieldBinding fieldBinding) { + countLabels = 0; + int id; + if (((id = fieldBinding.type.id) == T_double) || (id == T_long)) + stackDepth -= 2; + else + stackDepth -= 1; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_putstatic; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_putstatic); + } + writeUnsignedShort(constantPool.literalIndex(fieldBinding)); +} +public void record(LocalVariableBinding local) { + if (!generateLocalVariableTableAttributes) + return; + if (allLocalsCounter == locals.length) { + // resize the collection + System.arraycopy(locals, 0, (locals = new LocalVariableBinding[allLocalsCounter + LOCALS_INCREMENT]), 0, allLocalsCounter); + } + locals[allLocalsCounter++] = local; + local.initializationPCs = new int[4]; + local.initializationCount = 0; +} +public void recordPositionsFrom(int startPC, int sourcePos) { + + /* Record positions in the table, only if nothing has + * already been recorded. Since we output them on the way + * up (children first for more specific info) + * The pcToSourceMap table is always sorted. + */ + + if (!generateLineNumberAttributes) + return; + if (sourcePos == 0) + return; + + // no code generated for this node. e.g. field without any initialization + if (position == startPC) + return; + + // Widening an existing entry that already has the same source positions + if (pcToSourceMapSize + 4 > pcToSourceMap.length) { + // resize the array pcToSourceMap + System.arraycopy(pcToSourceMap, 0, (pcToSourceMap = new int[pcToSourceMapSize << 1]), 0, pcToSourceMapSize); + } + int newLine = ClassFile.searchLineNumber(lineSeparatorPositions, sourcePos); + // lastEntryPC represents the endPC of the lastEntry. + if (pcToSourceMapSize > 0) { + // in this case there is already an entry in the table + if (pcToSourceMap[pcToSourceMapSize - 1] != newLine) { + if (startPC < lastEntryPC) { + // we forgot to add an entry. + // search if an existing entry exists for startPC + int insertionIndex = insertionIndex(pcToSourceMap, pcToSourceMapSize, startPC); + if (insertionIndex != -1) { + // there is no existing entry starting with startPC. + int existingEntryIndex = indexOfSameLineEntrySincePC(startPC, newLine); // index for PC + /* the existingEntryIndex corresponds to en entry with the same line and a PC >= startPC. + in this case it is relevant to widen this entry instead of creating a new one. + line1: this(a, + b, + c); + with this code we generate each argument. We generate a aload0 to invoke the constructor. There is no entry for this + aload0 bytecode. The first entry is the one for the argument a. + But we want the constructor call to start at the aload0 pc and not just at the pc of the first argument. + So we widen the existing entry (if there is one) or we create a new entry with the startPC. + */ + if (existingEntryIndex != -1) { + // widen existing entry + pcToSourceMap[existingEntryIndex] = startPC; + } else { + // we have to add an entry that won't be sorted. So we sort the pcToSourceMap. + System.arraycopy(pcToSourceMap, insertionIndex, pcToSourceMap, insertionIndex + 2, pcToSourceMapSize - insertionIndex); + pcToSourceMap[insertionIndex++] = startPC; + pcToSourceMap[insertionIndex] = newLine; + pcToSourceMapSize += 2; + } + } + if (position != lastEntryPC) { // no bytecode since last entry pc + pcToSourceMap[pcToSourceMapSize++] = lastEntryPC; + pcToSourceMap[pcToSourceMapSize++] = newLine; + } + } else { + // we can safely add the new entry. The endPC of the previous entry is not in conflit with the startPC of the new entry. + pcToSourceMap[pcToSourceMapSize++] = startPC; + pcToSourceMap[pcToSourceMapSize++] = newLine; + } + } else { + /* the last recorded entry is on the same line. But it could be relevant to widen this entry. + we want to extend this entry forward in case we generated some bytecode before the last entry that are not related to any statement + */ + if (startPC < pcToSourceMap[pcToSourceMapSize - 2]) { + int insertionIndex = insertionIndex(pcToSourceMap, pcToSourceMapSize, startPC); + if (insertionIndex != -1) { + // widen the existing entry + // we have to figure out if we need to move the last entry at another location to keep a sorted table + if ((pcToSourceMapSize > 4) && (pcToSourceMap[pcToSourceMapSize - 4] > startPC)) { + System.arraycopy(pcToSourceMap, insertionIndex, pcToSourceMap, insertionIndex + 2, pcToSourceMapSize - 2 - insertionIndex); + pcToSourceMap[insertionIndex++] = startPC; + pcToSourceMap[insertionIndex] = newLine; + } else { + pcToSourceMap[pcToSourceMapSize - 2] = startPC; + } + } + } + } + lastEntryPC = position; + } else { + // record the first entry + pcToSourceMap[pcToSourceMapSize++] = startPC; + pcToSourceMap[pcToSourceMapSize++] = newLine; + lastEntryPC = position; + } +} +/** + * @param anExceptionLabel org.eclipse.jdt.internal.compiler.codegen.ExceptionLabel + */ +public void registerExceptionHandler(ExceptionLabel anExceptionLabel) { + int length; + if (exceptionHandlersNumber >= (length = exceptionHandlers.length)) { + // resize the exception handlers table + System.arraycopy(exceptionHandlers, 0, exceptionHandlers = new ExceptionLabel[length + LABELS_INCREMENT], 0, length); + } + // no need to resize. So just add the new exception label + exceptionHandlers[exceptionHandlersNumber++] = anExceptionLabel; +} +public final void removeNotDefinitelyAssignedVariables(Scope scope, int initStateIndex) { + // given some flow info, make sure we did not loose some variables initialization + // if this happens, then we must update their pc entries to reflect it in debug attributes + if (!generateLocalVariableTableAttributes) + return; +/* if (initStateIndex == lastInitStateIndexWhenRemovingInits) + return; + + lastInitStateIndexWhenRemovingInits = initStateIndex; + if (lastInitStateIndexWhenAddingInits != initStateIndex){ + lastInitStateIndexWhenAddingInits = -2;// reinitialize add index + // add(1)-remove(1)-add(1) -> ignore second add + // add(1)-remove(2)-add(1) -> perform second add + }*/ + for (int i = 0; i < visibleLocalsCount; i++) { + LocalVariableBinding localBinding = visibleLocals[i]; + if (localBinding != null) { + if (initStateIndex == -1 || !isDefinitelyAssigned(scope, initStateIndex, localBinding)) { + if (localBinding.initializationCount > 0) { + localBinding.recordInitializationEndPC(position); + } + } + } + } +} +/** + * @param methodDeclaration org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration + * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile + */ +public void reset(AbstractMethodDeclaration methodDeclaration, ClassFile classFile) { + init(classFile); + this.methodDeclaration = methodDeclaration; + preserveUnusedLocals = methodDeclaration.scope.problemReporter().options.preserveAllLocalVariables; + initializeMaxLocals(methodDeclaration.binding); +} +/** + * @param methodDeclaration org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration + * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile + */ +public void resetForProblemClinit(ClassFile classFile) { + init(classFile); + maxLocals = 0; +} +protected final void resizeByteArray() { + int actualLength = bCodeStream.length; + int requiredSize = actualLength + growFactor; + if (classFileOffset > requiredSize) { + requiredSize = classFileOffset + growFactor; + } + System.arraycopy(bCodeStream, 0, (bCodeStream = new byte[requiredSize]), 0, actualLength); +} +/** + * This method is used to resize the internal byte array in + * case of a ArrayOutOfBoundsException when adding the value b. + * Resize and add the new byte b inside the array. + * @param b byte + */ +protected final void resizeByteArray(byte b) { + resizeByteArray(); + bCodeStream[classFileOffset - 1] = b; +} +final public void ret(int index) { + countLabels = 0; + if (index > 255) { // Widen + try { + position++; + bCodeStream[classFileOffset++] = OPC_wide; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_wide); + } + try { + position++; + bCodeStream[classFileOffset++] = OPC_ret; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ret); + } + writeUnsignedShort(index); + } else { // Don't Widen + try { + position++; + bCodeStream[classFileOffset++] = OPC_ret; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_ret); + } + try { + position++; + bCodeStream[classFileOffset++] = (byte) index; + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) index); + } + } +} +final public void return_() { + countLabels = 0; + // the stackDepth should be equal to 0 + try { + position++; + bCodeStream[classFileOffset++] = OPC_return; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_return); + } +} +final public void saload() { + countLabels = 0; + stackDepth--; + try { + position++; + bCodeStream[classFileOffset++] = OPC_saload; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_saload); + } +} +final public void sastore() { + countLabels = 0; + stackDepth -= 3; + try { + position++; + bCodeStream[classFileOffset++] = OPC_sastore; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_sastore); + } +} +/** + * @param operatorConstant int + * @param type_ID int + */ +public void sendOperator(int operatorConstant, int type_ID) { + switch (type_ID) { + case T_int : + case T_boolean : + case T_char : + case T_byte : + case T_short : + switch (operatorConstant) { + case PLUS : + this.iadd(); + break; + case MINUS : + this.isub(); + break; + case MULTIPLY : + this.imul(); + break; + case DIVIDE : + this.idiv(); + break; + case REMAINDER : + this.irem(); + break; + case LEFT_SHIFT : + this.ishl(); + break; + case RIGHT_SHIFT : + this.ishr(); + break; + case UNSIGNED_RIGHT_SHIFT : + this.iushr(); + break; + case AND : + this.iand(); + break; + case OR : + this.ior(); + break; + case XOR : + this.ixor(); + break; + } + break; + case T_long : + switch (operatorConstant) { + case PLUS : + this.ladd(); + break; + case MINUS : + this.lsub(); + break; + case MULTIPLY : + this.lmul(); + break; + case DIVIDE : + this.ldiv(); + break; + case REMAINDER : + this.lrem(); + break; + case LEFT_SHIFT : + this.lshl(); + break; + case RIGHT_SHIFT : + this.lshr(); + break; + case UNSIGNED_RIGHT_SHIFT : + this.lushr(); + break; + case AND : + this.land(); + break; + case OR : + this.lor(); + break; + case XOR : + this.lxor(); + break; + } + break; + case T_float : + switch (operatorConstant) { + case PLUS : + this.fadd(); + break; + case MINUS : + this.fsub(); + break; + case MULTIPLY : + this.fmul(); + break; + case DIVIDE : + this.fdiv(); + break; + case REMAINDER : + this.frem(); + } + break; + case T_double : + switch (operatorConstant) { + case PLUS : + this.dadd(); + break; + case MINUS : + this.dsub(); + break; + case MULTIPLY : + this.dmul(); + break; + case DIVIDE : + this.ddiv(); + break; + case REMAINDER : + this.drem(); + } + } +} +final public void sipush(int s) { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + try { + position++; + bCodeStream[classFileOffset++] = OPC_sipush; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_sipush); + } + writeSignedShort(s); +} +public static final void sort(int[] tab, int lo0, int hi0, int[] result) { + int lo = lo0; + int hi = hi0; + int mid; + if (hi0 > lo0) { + /* Arbitrarily establishing partition element as the midpoint of + * the array. + */ + mid = tab[ (lo0 + hi0) / 2]; + // loop through the array until indices cross + while (lo <= hi) { + /* find the first element that is greater than or equal to + * the partition element starting from the left Index. + */ + while ((lo < hi0) && (tab[lo] < mid)) + ++lo; + /* find an element that is smaller than or equal to + * the partition element starting from the right Index. + */ + while ((hi > lo0) && (tab[hi] > mid)) + --hi; + // if the indexes have not crossed, swap + if (lo <= hi) { + swap(tab, lo, hi, result); + ++lo; + --hi; + } + } + /* If the right index has not reached the left side of array + * must now sort the left partition. + */ + if (lo0 < hi) + sort(tab, lo0, hi, result); + /* If the left index has not reached the right side of array + * must now sort the right partition. + */ + if (lo < hi0) + sort(tab, lo, hi0, result); + } +} +public final void store(LocalVariableBinding localBinding, boolean valueRequired) { + TypeBinding type = localBinding.type; + int position = localBinding.resolvedPosition; + // Using dedicated int bytecode + if ((type == IntBinding) || (type == CharBinding) || (type == ByteBinding) || (type == ShortBinding) || (type == BooleanBinding)) { + if (valueRequired) + this.dup(); + switch (position) { + case 0 : + this.istore_0(); + break; + case 1 : + this.istore_1(); + break; + case 2 : + this.istore_2(); + break; + case 3 : + this.istore_3(); + break; + default : + this.istore(position); + } + return; + } + // Using dedicated float bytecode + if (type == FloatBinding) { + if (valueRequired) + this.dup(); + switch (position) { + case 0 : + this.fstore_0(); + break; + case 1 : + this.fstore_1(); + break; + case 2 : + this.fstore_2(); + break; + case 3 : + this.fstore_3(); + break; + default : + this.fstore(position); + } + return; + } + // Using dedicated long bytecode + if (type == LongBinding) { + if (valueRequired) + this.dup2(); + switch (position) { + case 0 : + this.lstore_0(); + break; + case 1 : + this.lstore_1(); + break; + case 2 : + this.lstore_2(); + break; + case 3 : + this.lstore_3(); + break; + default : + this.lstore(position); + } + return; + } + // Using dedicated double bytecode + if (type == DoubleBinding) { + if (valueRequired) + this.dup2(); + switch (position) { + case 0 : + this.dstore_0(); + break; + case 1 : + this.dstore_1(); + break; + case 2 : + this.dstore_2(); + break; + case 3 : + this.dstore_3(); + break; + default : + this.dstore(position); + } + return; + } + // Reference object + if (valueRequired) + this.dup(); + switch (position) { + case 0 : + this.astore_0(); + break; + case 1 : + this.astore_1(); + break; + case 2 : + this.astore_2(); + break; + case 3 : + this.astore_3(); + break; + default : + this.astore(position); + } +} +public final void store(TypeBinding type, int position) { + // Using dedicated int bytecode + if ((type == IntBinding) || (type == CharBinding) || (type == ByteBinding) || (type == ShortBinding) || (type == BooleanBinding)) { + switch (position) { + case 0 : + this.istore_0(); + break; + case 1 : + this.istore_1(); + break; + case 2 : + this.istore_2(); + break; + case 3 : + this.istore_3(); + break; + default : + this.istore(position); + } + return; + } + // Using dedicated float bytecode + if (type == FloatBinding) { + switch (position) { + case 0 : + this.fstore_0(); + break; + case 1 : + this.fstore_1(); + break; + case 2 : + this.fstore_2(); + break; + case 3 : + this.fstore_3(); + break; + default : + this.fstore(position); + } + return; + } + // Using dedicated long bytecode + if (type == LongBinding) { + switch (position) { + case 0 : + this.lstore_0(); + break; + case 1 : + this.lstore_1(); + break; + case 2 : + this.lstore_2(); + break; + case 3 : + this.lstore_3(); + break; + default : + this.lstore(position); + } + return; + } + // Using dedicated double bytecode + if (type == DoubleBinding) { + switch (position) { + case 0 : + this.dstore_0(); + break; + case 1 : + this.dstore_1(); + break; + case 2 : + this.dstore_2(); + break; + case 3 : + this.dstore_3(); + break; + default : + this.dstore(position); + } + return; + } + // Reference object + switch (position) { + case 0 : + this.astore_0(); + break; + case 1 : + this.astore_1(); + break; + case 2 : + this.astore_2(); + break; + case 3 : + this.astore_3(); + break; + default : + this.astore(position); + } +} +public final void storeInt(int position) { + switch (position) { + case 0 : + this.istore_0(); + break; + case 1 : + this.istore_1(); + break; + case 2 : + this.istore_2(); + break; + case 3 : + this.istore_3(); + break; + default : + this.istore(position); + } +} +public final void storeObject(int position) { + switch (position) { + case 0 : + this.astore_0(); + break; + case 1 : + this.astore_1(); + break; + case 2 : + this.astore_2(); + break; + case 3 : + this.astore_3(); + break; + default : + this.astore(position); + } +} +final public void swap() { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_swap; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_swap); + } +} +private static final void swap(int a[], int i, int j, int result[]) { + int T; + T = a[i]; + a[i] = a[j]; + a[j] = T; + T = result[j]; + result[j] = result[i]; + result[i] = T; +} +final public void tableswitch(CaseLabel defaultLabel, int low, int high, int[] keys, int[] sortedIndexes, CaseLabel[] casesLabel) { + countLabels = 0; + stackDepth--; + int length = casesLabel.length; + int pos = position; + defaultLabel.placeInstruction(); + for (int i = 0; i < length; i++) + casesLabel[i].placeInstruction(); + try { + position++; + bCodeStream[classFileOffset++] = OPC_tableswitch; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_tableswitch); + } + for (int i = (3 - (pos % 4)); i > 0; i--) { + position++; // Padding + classFileOffset++; + } + defaultLabel.branch(); + writeSignedWord(low); + writeSignedWord(high); + int i = low, j = low; + // the index j is used to know if the index i is one of the missing entries in case of an + // optimized tableswitch + while (true) { + int index; + int key = keys[index = sortedIndexes[j - low]]; + if (key == i) { + casesLabel[index].branch(); + j++; + if (i == high) break; // if high is maxint, then avoids wrapping to minint. + } else { + defaultLabel.branch(); + } + i++; + } +} +public String toString() { + StringBuffer buffer = new StringBuffer("( position:"); //$NON-NLS-1$ + buffer.append(position); + buffer.append(",\nstackDepth:"); //$NON-NLS-1$ + buffer.append(stackDepth); + buffer.append(",\nmaxStack:"); //$NON-NLS-1$ + buffer.append(stackMax); + buffer.append(",\nmaxLocals:"); //$NON-NLS-1$ + buffer.append(maxLocals); + buffer.append(")"); //$NON-NLS-1$ + return buffer.toString(); +} +public void updateLastRecordedEndPC(int pos) { + + /* Tune positions in the table, this is due to some + * extra bytecodes being + * added to some user code (jumps). */ + /** OLD CODE + if (!generateLineNumberAttributes) + return; + pcToSourceMap[pcToSourceMapSize - 1][1] = position; + // need to update the initialization endPC in case of generation of local variable attributes. + updateLocalVariablesAttribute(pos); + */ + + if (!generateLineNumberAttributes) + return; + // need to update the initialization endPC in case of generation of local variable attributes. + updateLocalVariablesAttribute(pos); +} +public void updateLocalVariablesAttribute(int pos) { + // need to update the initialization endPC in case of generation of local variable attributes. + if (generateLocalVariableTableAttributes) { + for (int i = 0, max = locals.length; i < max; i++) { + LocalVariableBinding local = locals[i]; + if ((local != null) && (local.initializationCount > 0)) { + if (local.initializationPCs[((local.initializationCount - 1) << 1) + 1] == pos) { + local.initializationPCs[((local.initializationCount - 1) << 1) + 1] = position; + } + } + } + } +} +final public void wide() { + countLabels = 0; + try { + position++; + bCodeStream[classFileOffset++] = OPC_wide; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(OPC_wide); + } +} +public final void writeByte(byte b) { + try { + position++; + bCodeStream[classFileOffset++] = b; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(b); + } +} +public final void writeByteAtPos(int pos, byte b) { + try { + bCodeStream[pos] = b; + } catch (IndexOutOfBoundsException ex) { + resizeByteArray(); + bCodeStream[pos] = b; + } +} +/** + * Write a unsigned 8 bits value into the byte array + * @param b the signed byte + */ +public final void writeSignedByte(int b) { + try { + position++; + bCodeStream[classFileOffset++] = (byte) b; + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) b); + } +} +/** + * Write a signed 16 bits value into the byte array + * @param b the signed short + */ +public final void writeSignedShort(int b) { + try { + position++; + bCodeStream[classFileOffset++] = (byte) (b >> 8); + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) (b >> 8)); + } + try { + position++; + bCodeStream[classFileOffset++] = (byte) b; + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) b); + } +} +public final void writeSignedShort(int pos, int b) { + int currentOffset = startingClassFileOffset + pos; + try { + bCodeStream[currentOffset] = (byte) (b >> 8); + } catch (IndexOutOfBoundsException e) { + resizeByteArray(); + bCodeStream[currentOffset] = (byte) (b >> 8); + } + try { + bCodeStream[currentOffset + 1] = (byte) b; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(); + bCodeStream[currentOffset + 1] = (byte) b; + } +} +public final void writeSignedWord(int value) { + try { + position++; + bCodeStream[classFileOffset++] = (byte) ((value & 0xFF000000) >> 24); + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) ((value & 0xFF000000) >> 24)); + } + try { + position++; + bCodeStream[classFileOffset++] = (byte) ((value & 0xFF0000) >> 16); + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) ((value & 0xFF0000) >> 16)); + } + try { + position++; + bCodeStream[classFileOffset++] = (byte) ((value & 0xFF00) >> 8); + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) ((value & 0xFF00) >> 8)); + } + try { + position++; + bCodeStream[classFileOffset++] = (byte) (value & 0xFF); + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) (value & 0xFF)); + } +} +public final void writeSignedWord(int pos, int value) { + int currentOffset = startingClassFileOffset + pos; + try { + bCodeStream[currentOffset++] = (byte) ((value & 0xFF000000) >> 24); + } catch (IndexOutOfBoundsException e) { + resizeByteArray(); + bCodeStream[currentOffset-1] = (byte) ((value & 0xFF000000) >> 24); + } + try { + bCodeStream[currentOffset++] = (byte) ((value & 0xFF0000) >> 16); + } catch (IndexOutOfBoundsException e) { + resizeByteArray(); + bCodeStream[currentOffset-1] = (byte) ((value & 0xFF0000) >> 16); + } + try { + bCodeStream[currentOffset++] = (byte) ((value & 0xFF00) >> 8); + } catch (IndexOutOfBoundsException e) { + resizeByteArray(); + bCodeStream[currentOffset-1] = (byte) ((value & 0xFF00) >> 8); + } + try { + bCodeStream[currentOffset++] = (byte) (value & 0xFF); + } catch (IndexOutOfBoundsException e) { + resizeByteArray(); + bCodeStream[currentOffset-1] = (byte) (value & 0xFF); + } +} +/** + * Write a unsigned 8 bits value into the byte array + * @param b the unsigned byte + */ +public final void writeUnsignedByte(int b) { + try { + position++; + bCodeStream[classFileOffset++] = (byte) b; + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) b); + } +} +/** + * Write a unsigned 16 bits value into the byte array + * @param b the unsigned short + */ +public final void writeUnsignedShort(int b) { + try { + position++; + bCodeStream[classFileOffset++] = (byte) (b >>> 8); + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) (b >>> 8)); + } + try { + position++; + bCodeStream[classFileOffset++] = (byte) b; + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) b); + } +} +/** + * Write a unsigned 32 bits value into the byte array + * @param value the unsigned word + */ +public final void writeUnsignedWord(int value) { + try { + position++; + bCodeStream[classFileOffset++] = (byte) (value >>> 24); + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) (value >>> 24)); + } + try { + position++; + bCodeStream[classFileOffset++] = (byte) (value >>> 16); + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) (value >>> 16)); + } + try { + position++; + bCodeStream[classFileOffset++] = (byte) (value >>> 8); + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) (value >>> 8)); + } + try { + position++; + bCodeStream[classFileOffset++] = (byte) value; + } catch (IndexOutOfBoundsException e) { + resizeByteArray((byte) value); + } +} + +public void generateWideConditionalBranch(byte opcode, Label lbl) { + /* we handle the goto_w problem inside an if.... with some macro expansion + * at the bytecode level + * instead of: + * if_...... lbl + * we have: + * ifne + * goto + * l1 gotow // l3 is a wide target + * l2 .... + */ + Label l1 = new Label(this); + try { + position++; + bCodeStream[classFileOffset++] = opcode; + } catch (IndexOutOfBoundsException e) { + resizeByteArray(opcode); + } + l1.branch(); + Label l2 = new Label(this); + this.internal_goto_(l2); + l1.place(); + this.goto_w(lbl); + l2.place(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/ConstantPool.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/ConstantPool.java new file mode 100644 index 0000000..2d9ec90 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/ConstantPool.java @@ -0,0 +1,3120 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.codegen; + +import net.sourceforge.phpdt.internal.compiler.ClassFile; + +import net.sourceforge.phpdt.internal.compiler.classfmt.ClassFileConstants; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.util.*; + +/** + * This type is used to store all the constant pool entries. + */ +public class ConstantPool implements ClassFileConstants, TypeIds { + public static final int DOUBLE_INITIAL_SIZE = 5; + public static final int FLOAT_INITIAL_SIZE = 3; + public static final int INT_INITIAL_SIZE = 248; + public static final int LONG_INITIAL_SIZE = 5; + public static final int UTF8_INITIAL_SIZE = 778; + public static final int STRING_INITIAL_SIZE = 761; + public static final int FIELD_INITIAL_SIZE = 156; + public static final int METHOD_INITIAL_SIZE = 236; + public static final int INTERFACE_INITIAL_SIZE = 50; + public static final int CLASS_INITIAL_SIZE = 86; + public static final int NAMEANDTYPE_INITIAL_SIZE = 272; + public static final int CONSTANTPOOL_INITIAL_SIZE = 2000; + public static final int CONSTANTPOOL_GROW_SIZE = 6000; + protected DoubleCache doubleCache; + protected FloatCache floatCache; + protected IntegerCache intCache; + protected LongCache longCache; + public CharArrayCache UTF8Cache; + protected CharArrayCache stringCache; + protected ObjectCache fieldCache; + protected ObjectCache methodCache; + protected ObjectCache interfaceMethodCache; + protected ObjectCache classCache; + protected FieldNameAndTypeCache nameAndTypeCacheForFields; + protected MethodNameAndTypeCache nameAndTypeCacheForMethods; + int[] wellKnownTypes = new int[21]; + int[] wellKnownMethods = new int[36]; + int[] wellKnownFields = new int[10]; + int[] wellKnownFieldNameAndTypes = new int[2]; + int[] wellKnownMethodNameAndTypes = new int[33]; + public byte[] poolContent; + public int currentIndex = 1; + public int currentOffset; + // predefined constant index for well known types + final static int JAVA_LANG_BOOLEAN_TYPE = 0; + final static int JAVA_LANG_BYTE_TYPE = 1; + final static int JAVA_LANG_CHARACTER_TYPE = 2; + final static int JAVA_LANG_DOUBLE_TYPE = 3; + final static int JAVA_LANG_FLOAT_TYPE = 4; + final static int JAVA_LANG_INTEGER_TYPE = 5; + final static int JAVA_LANG_LONG_TYPE = 6; + final static int JAVA_LANG_SHORT_TYPE = 7; + final static int JAVA_LANG_VOID_TYPE = 8; + final static int JAVA_LANG_CLASS_TYPE = 9; + final static int JAVA_LANG_CLASSNOTFOUNDEXCEPTION_TYPE = 10; + final static int JAVA_LANG_NOCLASSDEFFOUNDERROR_TYPE = 11; + final static int JAVA_LANG_OBJECT_TYPE = 12; + final static int JAVA_LANG_STRING_TYPE = 13; + final static int JAVA_LANG_STRINGBUFFER_TYPE = 14; + final static int JAVA_LANG_SYSTEM_TYPE = 15; + final static int JAVA_LANG_THROWABLE_TYPE = 16; + final static int JAVA_LANG_ERROR_TYPE = 17; + final static int JAVA_LANG_EXCEPTION_TYPE = 18; + final static int JAVA_LANG_REFLECT_CONSTRUCTOR_TYPE = 19; + final static int JAVA_LANG_ASSERTIONERROR_TYPE = 20; + + // predefined constant index for well known fields + final static int TYPE_BYTE_FIELD = 0; + final static int TYPE_SHORT_FIELD = 1; + final static int TYPE_CHARACTER_FIELD = 2; + final static int TYPE_INTEGER_FIELD = 3; + final static int TYPE_LONG_FIELD = 4; + final static int TYPE_FLOAT_FIELD = 5; + final static int TYPE_DOUBLE_FIELD = 6; + final static int TYPE_BOOLEAN_FIELD = 7; + final static int TYPE_VOID_FIELD = 8; + final static int OUT_SYSTEM_FIELD = 9; + // predefined constant index for well known methods + final static int FORNAME_CLASS_METHOD = 0; + final static int NOCLASSDEFFOUNDERROR_CONSTR_METHOD = 1; + final static int APPEND_INT_METHOD = 2; + final static int APPEND_FLOAT_METHOD = 3; + final static int APPEND_LONG_METHOD = 4; + final static int APPEND_OBJECT_METHOD = 5; + final static int APPEND_CHAR_METHOD = 6; + final static int APPEND_STRING_METHOD = 7; + final static int APPEND_BOOLEAN_METHOD = 8; + final static int APPEND_DOUBLE_METHOD = 9; + final static int STRINGBUFFER_STRING_CONSTR_METHOD = 10; + final static int STRINGBUFFER_DEFAULT_CONSTR_METHOD = 11; + final static int STRINGBUFFER_TOSTRING_METHOD = 12; + final static int SYSTEM_EXIT_METHOD = 13; + final static int THROWABLE_GETMESSAGE_METHOD = 14; + final static int JAVALANGERROR_CONSTR_METHOD = 15; + final static int GETCONSTRUCTOR_CLASS_METHOD = 16; + final static int NEWINSTANCE_CONSTRUCTOR_METHOD = 17; + final static int STRING_INTERN_METHOD = 18; + final static int VALUEOF_INT_METHOD = 19; + final static int VALUEOF_FLOAT_METHOD = 20; + final static int VALUEOF_LONG_METHOD = 21; + final static int VALUEOF_OBJECT_METHOD = 22; + final static int VALUEOF_CHAR_METHOD = 23; + final static int VALUEOF_BOOLEAN_METHOD = 24; + final static int VALUEOF_DOUBLE_METHOD = 25; + final static int ASSERTIONERROR_CONSTR_OBJECT_METHOD = 26; + final static int ASSERTIONERROR_CONSTR_INT_METHOD = 27; + final static int ASSERTIONERROR_CONSTR_LONG_METHOD = 28; + final static int ASSERTIONERROR_CONSTR_FLOAT_METHOD = 29; + final static int ASSERTIONERROR_CONSTR_DOUBLE_METHOD = 30; + final static int ASSERTIONERROR_CONSTR_BOOLEAN_METHOD = 31; + final static int ASSERTIONERROR_CONSTR_CHAR_METHOD = 32; + final static int ASSERTIONERROR_DEFAULT_CONSTR_METHOD = 33; + final static int DESIREDASSERTIONSTATUS_CLASS_METHOD = 34; + final static int GETCLASS_OBJECT_METHOD = 35; + // predefined constant index for well known name and type for fields + final static int TYPE_JAVALANGCLASS_NAME_AND_TYPE = 0; + final static int OUT_SYSTEM_NAME_AND_TYPE = 1; + // predefined constant index for well known name and type for methods + final static int FORNAME_CLASS_METHOD_NAME_AND_TYPE = 0; + final static int CONSTR_STRING_METHOD_NAME_AND_TYPE = 1; + final static int DEFAULT_CONSTR_METHOD_NAME_AND_TYPE = 2; + final static int APPEND_INT_METHOD_NAME_AND_TYPE = 3; + final static int APPEND_FLOAT_METHOD_NAME_AND_TYPE = 4; + final static int APPEND_LONG_METHOD_NAME_AND_TYPE = 5; + final static int APPEND_OBJECT_METHOD_NAME_AND_TYPE = 6; + final static int APPEND_CHAR_METHOD_NAME_AND_TYPE = 7; + final static int APPEND_STRING_METHOD_NAME_AND_TYPE = 8; + final static int APPEND_BOOLEAN_METHOD_NAME_AND_TYPE = 9; + final static int APPEND_DOUBLE_METHOD_NAME_AND_TYPE = 10; + final static int TOSTRING_METHOD_NAME_AND_TYPE = 11; + final static int EXIT_METHOD_NAME_AND_TYPE = 12; + final static int GETMESSAGE_METHOD_NAME_AND_TYPE = 13; + final static int GETCONSTRUCTOR_METHOD_NAME_AND_TYPE = 14; + final static int NEWINSTANCE_METHOD_NAME_AND_TYPE = 15; + final static int INTERN_METHOD_NAME_AND_TYPE = 16; + final static int VALUEOF_INT_METHOD_NAME_AND_TYPE = 17; + final static int VALUEOF_FLOAT_METHOD_NAME_AND_TYPE = 18; + final static int VALUEOF_LONG_METHOD_NAME_AND_TYPE = 19; + final static int VALUEOF_OBJECT_METHOD_NAME_AND_TYPE = 20; + final static int VALUEOF_CHAR_METHOD_NAME_AND_TYPE = 21; + final static int VALUEOF_BOOLEAN_METHOD_NAME_AND_TYPE = 22; + final static int VALUEOF_DOUBLE_METHOD_NAME_AND_TYPE = 23; + final static int CONSTR_INT_METHOD_NAME_AND_TYPE = 24; + final static int CONSTR_LONG_METHOD_NAME_AND_TYPE = 25; + final static int CONSTR_FLOAT_METHOD_NAME_AND_TYPE = 26; + final static int CONSTR_DOUBLE_METHOD_NAME_AND_TYPE = 27; + final static int CONSTR_OBJECT_METHOD_NAME_AND_TYPE = 28; + final static int CONSTR_CHAR_METHOD_NAME_AND_TYPE = 29; + final static int CONSTR_BOOLEAN_METHOD_NAME_AND_TYPE = 30; + final static int DESIREDASSERTIONSTATUS_METHOD_NAME_AND_TYPE = 31; + final static int GETCLASS_OBJECT_METHOD_NAME_AND_TYPE = 32; + + + public ClassFile classFile; + +/** + * ConstantPool constructor comment. + */ +public ConstantPool(ClassFile classFile) { + this.UTF8Cache = new CharArrayCache(UTF8_INITIAL_SIZE); + this.stringCache = new CharArrayCache(STRING_INITIAL_SIZE); + this.fieldCache = new ObjectCache(FIELD_INITIAL_SIZE); + this.methodCache = new ObjectCache(METHOD_INITIAL_SIZE); + this.interfaceMethodCache = new ObjectCache(INTERFACE_INITIAL_SIZE); + this.classCache = new ObjectCache(CLASS_INITIAL_SIZE); + this.nameAndTypeCacheForMethods = new MethodNameAndTypeCache(NAMEANDTYPE_INITIAL_SIZE); + this.nameAndTypeCacheForFields = new FieldNameAndTypeCache(NAMEANDTYPE_INITIAL_SIZE); + this.poolContent = classFile.header; + this.currentOffset = classFile.headerOffset; + // currentOffset is initialized to 0 by default + this.currentIndex = 1; + this.classFile = classFile; +} +/** + * Return the content of the receiver + */ +public byte[] dumpBytes() { + System.arraycopy(poolContent, 0, (poolContent = new byte[currentOffset]), 0, currentOffset); + return poolContent; +} +/** + * Return the index of the @fieldBinding. + * + * Returns -1 if the @fieldBinding is not a predefined fieldBinding, + * the right index otherwise. + * + * @param fieldBinding org.eclipse.jdt.internal.compiler.lookup.FieldBinding + * @return int + */ +public int indexOfWellKnownFieldNameAndType(FieldBinding fieldBinding) { + if ((fieldBinding.type.id == T_JavaLangClass) && (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE))) + return TYPE_JAVALANGCLASS_NAME_AND_TYPE; + if ((fieldBinding.type.id == T_JavaIoPrintStream) && (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.Out))) + return OUT_SYSTEM_NAME_AND_TYPE; + return -1; +} +/** + * Return the index of the @fieldBinding. + * + * Returns -1 if the @fieldBinding is not a predefined fieldBinding, + * the right index otherwise. + * + * @param fieldBinding org.eclipse.jdt.internal.compiler.lookup.FieldBinding + * @return int + */ +public int indexOfWellKnownFields(FieldBinding fieldBinding) { + switch (fieldBinding.declaringClass.id) { + case T_JavaLangByte : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE)) + return TYPE_BYTE_FIELD; + break; + case T_JavaLangShort : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE)) + return TYPE_SHORT_FIELD; + break; + case T_JavaLangCharacter : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE)) + return TYPE_CHARACTER_FIELD; + break; + case T_JavaLangInteger : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE)) + return TYPE_INTEGER_FIELD; + break; + case T_JavaLangLong : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE)) + return TYPE_LONG_FIELD; + break; + case T_JavaLangFloat : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE)) + return TYPE_FLOAT_FIELD; + break; + case T_JavaLangDouble : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE)) + return TYPE_DOUBLE_FIELD; + break; + case T_JavaLangBoolean : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE)) + return TYPE_BOOLEAN_FIELD; + break; + case T_JavaLangVoid : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE)) + return TYPE_VOID_FIELD; + break; + case T_JavaLangSystem : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.Out)) + return OUT_SYSTEM_FIELD; + } + return -1; +} +/** + * Return the index of the @methodBinding. + * + * Returns -1 if the @methodBinding is not a predefined methodBinding, + * the right index otherwise. + * + * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding + * @return int + */ +public int indexOfWellKnownMethodNameAndType(MethodBinding methodBinding) { + char firstChar = methodBinding.selector[0]; + switch (firstChar) { + case 'f' : + if ((methodBinding.parameters.length == 1) && (methodBinding.parameters[0].id == T_JavaLangString) && (methodBinding.returnType.id == T_JavaLangClass) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.ForName))) { + // This method binding is forName(java.lang.String) + return FORNAME_CLASS_METHOD_NAME_AND_TYPE; + } + break; + case '<' : + if (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Init)) { + switch(methodBinding.parameters.length) { + case 1: + switch(methodBinding.parameters[0].id) { + case T_String : + if (CharOperation.equals(methodBinding.signature(), QualifiedNamesConstants.StringConstructorSignature)) { + return CONSTR_STRING_METHOD_NAME_AND_TYPE; + } else { + return -1; + } + case T_Object : + if (CharOperation.equals(methodBinding.signature(), QualifiedNamesConstants.AssertionErrorObjectConstrSignature)) { + return CONSTR_OBJECT_METHOD_NAME_AND_TYPE; + } else { + return -1; + } + case T_int : + if (CharOperation.equals(methodBinding.signature(), QualifiedNamesConstants.AssertionErrorIntConstrSignature)) { + return CONSTR_INT_METHOD_NAME_AND_TYPE; + } else { + return -1; + } + case T_char : + if (CharOperation.equals(methodBinding.signature(), QualifiedNamesConstants.AssertionErrorCharConstrSignature)) { + return CONSTR_CHAR_METHOD_NAME_AND_TYPE; + } else { + return -1; + } + case T_boolean : + if (CharOperation.equals(methodBinding.signature(), QualifiedNamesConstants.AssertionErrorBooleanConstrSignature)) { + return CONSTR_BOOLEAN_METHOD_NAME_AND_TYPE; + } else { + return -1; + } + case T_float : + if (CharOperation.equals(methodBinding.signature(), QualifiedNamesConstants.AssertionErrorFloatConstrSignature)) { + return CONSTR_FLOAT_METHOD_NAME_AND_TYPE; + } else { + return -1; + } + case T_double : + if (CharOperation.equals(methodBinding.signature(), QualifiedNamesConstants.AssertionErrorDoubleConstrSignature)) { + return CONSTR_DOUBLE_METHOD_NAME_AND_TYPE; + } else { + return -1; + } + case T_long : + if (CharOperation.equals(methodBinding.signature(), QualifiedNamesConstants.AssertionErrorLongConstrSignature)) { + return CONSTR_LONG_METHOD_NAME_AND_TYPE; + } else { + return -1; + } + } + case 0: + if (methodBinding.signature().length == 3) { + return DEFAULT_CONSTR_METHOD_NAME_AND_TYPE; + } + } + } + break; + case 'a' : + if ((methodBinding.parameters.length == 1) && (methodBinding.returnType.id == T_JavaLangStringBuffer) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Append))) { + switch (methodBinding.parameters[0].id) { + case T_int : + case T_byte : + case T_short : + // This method binding is append(int) + return APPEND_INT_METHOD_NAME_AND_TYPE; + case T_float : + // This method binding is append(float) + return APPEND_FLOAT_METHOD_NAME_AND_TYPE; + case T_long : + // This method binding is append(long) + return APPEND_LONG_METHOD_NAME_AND_TYPE; + case T_JavaLangObject : + // This method binding is append(java.lang.Object) + return APPEND_OBJECT_METHOD_NAME_AND_TYPE; + case T_char : + // This method binding is append(char) + return APPEND_CHAR_METHOD_NAME_AND_TYPE; + case T_JavaLangString : + // This method binding is append(java.lang.String) + return APPEND_STRING_METHOD_NAME_AND_TYPE; + case T_boolean : + // This method binding is append(boolean) + return APPEND_BOOLEAN_METHOD_NAME_AND_TYPE; + case T_double : + // This method binding is append(double) + return APPEND_DOUBLE_METHOD_NAME_AND_TYPE; + } + } + break; + case 't' : + if ((methodBinding.parameters.length == 0) && (methodBinding.returnType.id == T_JavaLangString) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.ToString))) { + // This method binding is toString() + return TOSTRING_METHOD_NAME_AND_TYPE; + } + break; + case 'v' : + if ((methodBinding.parameters.length == 1) && (methodBinding.returnType.id == T_JavaLangString) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.ValueOf))) { + switch(methodBinding.parameters[0].id) { + case T_Object: + return VALUEOF_OBJECT_METHOD_NAME_AND_TYPE; + case T_int: + case T_short: + case T_byte: + return VALUEOF_INT_METHOD_NAME_AND_TYPE; + case T_long: + return VALUEOF_LONG_METHOD_NAME_AND_TYPE; + case T_float: + return VALUEOF_FLOAT_METHOD_NAME_AND_TYPE; + case T_double: + return VALUEOF_DOUBLE_METHOD_NAME_AND_TYPE; + case T_boolean: + return VALUEOF_BOOLEAN_METHOD_NAME_AND_TYPE; + case T_char: + return VALUEOF_CHAR_METHOD_NAME_AND_TYPE; + } + } + break; + case 'e' : + if ((methodBinding.parameters.length == 1) && (methodBinding.parameters[0].id == T_int) && (methodBinding.returnType.id == T_void) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Exit))) { + // This method binding is exit(int) + return EXIT_METHOD_NAME_AND_TYPE; + } + break; + case 'g' : + if ((methodBinding.selector.length == 10) + && (methodBinding.parameters.length == 0) + && (methodBinding.returnType.id == T_JavaLangString) + && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.GetMessage))) { + // This method binding is getMessage() + return GETMESSAGE_METHOD_NAME_AND_TYPE; + } + if (methodBinding.parameters.length == 0 + && methodBinding.returnType.id == T_JavaLangClass + && CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.GetClass)) { + return GETCLASS_OBJECT_METHOD_NAME_AND_TYPE; + } + break; + case 'i' : + if ((methodBinding.parameters.length == 0) && (methodBinding.returnType.id == T_JavaLangString) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Intern))) { + // This method binding is toString() + return INTERN_METHOD_NAME_AND_TYPE; + } + } + return -1; +} +/** + * Return the index of the @methodBinding. + * + * Returns -1 if the @methodBinding is not a predefined methodBinding, + * the right index otherwise. + * + * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding + * @return int + */ +public int indexOfWellKnownMethods(MethodBinding methodBinding) { + char firstChar = methodBinding.selector[0]; + switch (methodBinding.declaringClass.id) { + case T_JavaLangClass : + if ((firstChar == 'f') && (methodBinding.isStatic()) && (methodBinding.parameters.length == 1) && (methodBinding.parameters[0].id == T_JavaLangString) && (methodBinding.returnType.id == T_JavaLangClass) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.ForName))) { + // This method binding is forName(java.lang.String) + return FORNAME_CLASS_METHOD; + } else if ((firstChar == 'g') && (methodBinding.parameters.length == 1) && (methodBinding.returnType.id == T_JavaLangReflectConstructor) && CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.GetConstructor) && CharOperation.equals(methodBinding.parameters[0].constantPoolName(), QualifiedNamesConstants.ArrayJavaLangClassConstantPoolName)) { + return GETCONSTRUCTOR_CLASS_METHOD; + } else if ((firstChar == 'd') && (methodBinding.parameters.length == 0) && (methodBinding.returnType.id == T_boolean) && CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.DesiredAssertionStatus)) { + return DESIREDASSERTIONSTATUS_CLASS_METHOD; + } + break; + case T_JavaLangNoClassDefError : + if ((firstChar == '<') && (methodBinding.parameters.length == 1) && (methodBinding.parameters[0].id == T_JavaLangString) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Init))) { + // This method binding is NoClassDefFoundError(java.lang.String) + return NOCLASSDEFFOUNDERROR_CONSTR_METHOD; + } + break; + case T_JavaLangReflectConstructor : + if ((firstChar == 'n') && (methodBinding.parameters.length == 1) && (methodBinding.returnType.id == T_JavaLangObject) && CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.NewInstance) && CharOperation.equals(methodBinding.parameters[0].constantPoolName(), QualifiedNamesConstants.ArrayJavaLangObjectConstantPoolName)) { + return NEWINSTANCE_CONSTRUCTOR_METHOD; + } + break; + case T_JavaLangStringBuffer : + if ((firstChar == 'a') && (methodBinding.parameters.length == 1) && (methodBinding.returnType.id == T_JavaLangStringBuffer) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Append))) { + switch (methodBinding.parameters[0].id) { + case T_int : + case T_byte : + case T_short : + // This method binding is append(int) + return APPEND_INT_METHOD; + case T_float : + // This method binding is append(float) + return APPEND_FLOAT_METHOD; + case T_long : + // This method binding is append(long) + return APPEND_LONG_METHOD; + case T_JavaLangObject : + // This method binding is append(java.lang.Object) + return APPEND_OBJECT_METHOD; + case T_char : + // This method binding is append(char) + return APPEND_CHAR_METHOD; + case T_JavaLangString : + // This method binding is append(java.lang.String) + return APPEND_STRING_METHOD; + case T_boolean : + // This method binding is append(boolean) + return APPEND_BOOLEAN_METHOD; + case T_double : + // This method binding is append(double) + return APPEND_DOUBLE_METHOD; + } + } else + if ((firstChar == 't') && (methodBinding.parameters.length == 0) && (methodBinding.returnType.id == T_JavaLangString) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.ToString))) { + // This method binding is toString() + return STRINGBUFFER_TOSTRING_METHOD; + } else + if ((firstChar == '<') && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Init))) { + if ((methodBinding.parameters.length == 1) && (methodBinding.parameters[0].id == T_JavaLangString)) { + // This method binding is (String) + return STRINGBUFFER_STRING_CONSTR_METHOD; + } else { + if (methodBinding.parameters.length == 0) { + // This method binding is () + return STRINGBUFFER_DEFAULT_CONSTR_METHOD; + } + } + } + break; + case T_JavaLangString : + if ((firstChar == 'v') && (methodBinding.parameters.length == 1) && (methodBinding.returnType.id == T_JavaLangString) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.ValueOf))) { + // This method binding is valueOf(java.lang.Object) + switch (methodBinding.parameters[0].id) { + case T_Object : + return VALUEOF_OBJECT_METHOD; + case T_int : + case T_short : + case T_byte : + return VALUEOF_INT_METHOD; + case T_long : + return VALUEOF_LONG_METHOD; + case T_float : + return VALUEOF_FLOAT_METHOD; + case T_double : + return VALUEOF_DOUBLE_METHOD; + case T_boolean : + return VALUEOF_BOOLEAN_METHOD; + case T_char : + return VALUEOF_CHAR_METHOD; + } + } else + if ((firstChar == 'i') && (methodBinding.parameters.length == 0) && (methodBinding.returnType.id == T_JavaLangString) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Intern))) { + // This method binding is valueOf(java.lang.Object) + return STRING_INTERN_METHOD; + } + break; + case T_JavaLangSystem : + if ((firstChar == 'e') && (methodBinding.parameters.length == 1) && (methodBinding.parameters[0].id == T_int) && (methodBinding.returnType.id == T_void) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Exit))) { + // This method binding is exit(int) + return SYSTEM_EXIT_METHOD; + } + break; + case T_JavaLangThrowable : + if ((firstChar == 'g') && (methodBinding.selector.length == 10) && (methodBinding.parameters.length == 0) && (methodBinding.returnType.id == T_JavaLangString) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.GetMessage))) { + // This method binding is getMessage() + return THROWABLE_GETMESSAGE_METHOD; + } + break; + case T_JavaLangError : + if ((firstChar == '<') && (methodBinding.parameters.length == 1) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Init)) && (methodBinding.parameters[0].id == T_String)) { + return JAVALANGERROR_CONSTR_METHOD; + } + break; + case T_JavaLangAssertionError : + if ((firstChar == '<') && CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Init)) { + switch (methodBinding.parameters.length) { + case 0: + return ASSERTIONERROR_DEFAULT_CONSTR_METHOD; + case 1: + switch(methodBinding.parameters[0].id) { + case T_boolean : + return ASSERTIONERROR_CONSTR_BOOLEAN_METHOD; + case T_char : + return ASSERTIONERROR_CONSTR_CHAR_METHOD; + case T_double : + return ASSERTIONERROR_CONSTR_DOUBLE_METHOD; + case T_int : + case T_byte : + case T_short : + return ASSERTIONERROR_CONSTR_INT_METHOD; + case T_float : + return ASSERTIONERROR_CONSTR_FLOAT_METHOD; + case T_long : + return ASSERTIONERROR_CONSTR_LONG_METHOD; + default: + return ASSERTIONERROR_CONSTR_OBJECT_METHOD; + } + } + } + break; + case T_JavaLangObject : + if (methodBinding.parameters.length == 0 + && CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.GetClass)) { + return GETCLASS_OBJECT_METHOD; + } + } + return -1; +} +/** + * Return the index of the @typeBinding + * + * Returns -1 if the @typeBinding is not a predefined binding, the right index + * otherwise. + * + * @param typeBinding org.eclipse.jdt.internal.compiler.lookup.TypeBinding + * @return int + */ +public int indexOfWellKnownTypes(TypeBinding typeBinding) { + switch(typeBinding.id) { + case T_JavaLangBoolean : return JAVA_LANG_BOOLEAN_TYPE; + case T_JavaLangByte : return JAVA_LANG_BYTE_TYPE; + case T_JavaLangCharacter : return JAVA_LANG_CHARACTER_TYPE; + case T_JavaLangDouble : return JAVA_LANG_DOUBLE_TYPE; + case T_JavaLangFloat : return JAVA_LANG_FLOAT_TYPE; + case T_JavaLangInteger : return JAVA_LANG_INTEGER_TYPE; + case T_JavaLangLong : return JAVA_LANG_LONG_TYPE; + case T_JavaLangShort : return JAVA_LANG_SHORT_TYPE; + case T_JavaLangVoid : return JAVA_LANG_VOID_TYPE; + case T_JavaLangClass : return JAVA_LANG_CLASS_TYPE; + case T_JavaLangClassNotFoundException : return JAVA_LANG_CLASSNOTFOUNDEXCEPTION_TYPE; + case T_JavaLangNoClassDefError : return JAVA_LANG_NOCLASSDEFFOUNDERROR_TYPE; + case T_JavaLangObject : return JAVA_LANG_OBJECT_TYPE; + case T_JavaLangString : return JAVA_LANG_STRING_TYPE; + case T_JavaLangStringBuffer : return JAVA_LANG_STRINGBUFFER_TYPE; + case T_JavaLangSystem : return JAVA_LANG_SYSTEM_TYPE; + case T_JavaLangThrowable : return JAVA_LANG_THROWABLE_TYPE; + case T_JavaLangError : return JAVA_LANG_ERROR_TYPE; + case T_JavaLangException : return JAVA_LANG_EXCEPTION_TYPE; + case T_JavaLangReflectConstructor : return JAVA_LANG_REFLECT_CONSTRUCTOR_TYPE; + case T_JavaLangAssertionError : return JAVA_LANG_ASSERTIONERROR_TYPE; + } + return -1; +} +public int literalIndex(byte[] utf8encoding, char[] stringCharArray) { + int index; + if ((index = UTF8Cache.get(stringCharArray)) < 0) { + // The entry doesn't exit yet + index = UTF8Cache.put(stringCharArray, currentIndex); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + currentIndex++; + // Write the tag first + writeU1(Utf8Tag); + // Then the size of the stringName array + //writeU2(utf8Constant.length); + int savedCurrentOffset = currentOffset; + if (currentOffset + 2 >= poolContent.length) { + // we need to resize the poolContent array because we won't have + // enough space to write the length + int length = poolContent.length; + System.arraycopy(poolContent, 0, (poolContent = new byte[length + CONSTANTPOOL_GROW_SIZE]), 0, length); + } + currentOffset += 2; + // add in once the whole byte array + int length = poolContent.length; + int utf8encodingLength = utf8encoding.length; + if (currentOffset + utf8encodingLength >= length) { + System.arraycopy(poolContent, 0, (poolContent = new byte[length + utf8encodingLength + CONSTANTPOOL_GROW_SIZE]), 0, length); + } + System.arraycopy(utf8encoding, 0, poolContent, currentOffset, utf8encodingLength); + currentOffset += utf8encodingLength; + // Now we know the length that we have to write in the constant pool + // we use savedCurrentOffset to do that + poolContent[savedCurrentOffset] = (byte) (utf8encodingLength >> 8); + poolContent[savedCurrentOffset + 1] = (byte) utf8encodingLength; + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param char[] stringName + * @return int + */ +public int literalIndex(char[] utf8Constant) { + int index; + if ((index = UTF8Cache.get(utf8Constant)) < 0) { + // The entry doesn't exit yet + // Write the tag first + writeU1(Utf8Tag); + // Then the size of the stringName array + int savedCurrentOffset = currentOffset; + if (currentOffset + 2 >= poolContent.length) { + // we need to resize the poolContent array because we won't have + // enough space to write the length + int length = poolContent.length; + System.arraycopy(poolContent, 0, (poolContent = new byte[length + CONSTANTPOOL_GROW_SIZE]), 0, length); + } + currentOffset += 2; + int length = 0; + for (int i = 0; i < utf8Constant.length; i++) { + char current = utf8Constant[i]; + if ((current >= 0x0001) && (current <= 0x007F)) { + // we only need one byte: ASCII table + writeU1(current); + length++; + } else + if (current > 0x07FF) { + // we need 3 bytes + length += 3; + writeU1(0xE0 | ((current >> 12) & 0x0F)); // 0xE0 = 1110 0000 + writeU1(0x80 | ((current >> 6) & 0x3F)); // 0x80 = 1000 0000 + writeU1(0x80 | (current & 0x3F)); // 0x80 = 1000 0000 + } else { + // we can be 0 or between 0x0080 and 0x07FF + // In that case we only need 2 bytes + length += 2; + writeU1(0xC0 | ((current >> 6) & 0x1F)); // 0xC0 = 1100 0000 + writeU1(0x80 | (current & 0x3F)); // 0x80 = 1000 0000 + } + } + if (length >= 65535) { + currentOffset = savedCurrentOffset - 1; + return -1; + } + index = UTF8Cache.put(utf8Constant, currentIndex); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + currentIndex++; + // Now we know the length that we have to write in the constant pool + // we use savedCurrentOffset to do that + poolContent[savedCurrentOffset] = (byte) (length >> 8); + poolContent[savedCurrentOffset + 1] = (byte) length; + } + return index; +} +public int literalIndex(char[] stringCharArray, byte[] utf8encoding) { + int index; + int stringIndex; + if ((index = stringCache.get(stringCharArray)) < 0) { + // The entry doesn't exit yet + stringIndex = literalIndex(utf8encoding, stringCharArray); + index = stringCache.put(stringCharArray, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the tag first + writeU1(StringTag); + // Then the string index + writeU2(stringIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the double + * value. If the double is not already present into the pool, it is added. The + * double cache is updated and it returns the right index. + * + * @param double key + * @return int + */ +public int literalIndex(double key) { + //Retrieve the index from the cache + // The double constant takes two indexes into the constant pool, but we only store + // the first index into the long table + int index; + // lazy initialization for base type caches + // If it is null, initialize it, otherwise use it + if (doubleCache == null) { + doubleCache = new DoubleCache(DOUBLE_INITIAL_SIZE); + } + if ((index = doubleCache.get(key)) < 0) { + index = doubleCache.put(key, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + currentIndex++; // a double needs an extra place into the constant pool + // Write the double into the constant pool + // First add the tag + writeU1(DoubleTag); + // Then add the 8 bytes representing the double + long temp = java.lang.Double.doubleToLongBits(key); + for (int i = 0; i < 8; i++) { + try { + poolContent[currentOffset++] = (byte) (temp >>> (56 - (i << 3))); + } catch (IndexOutOfBoundsException e) { //currentOffset has been ++ already (see the -1) + int length = poolContent.length; + System.arraycopy(poolContent, 0, (poolContent = new byte[(length << 1) + CONSTANTPOOL_INITIAL_SIZE]), 0, length); + poolContent[currentOffset - 1] = (byte) (temp >>> (56 - (i << 3))); + } + } + }; + return index; +} +/** + * This method returns the index into the constantPool corresponding to the float + * value. If the float is not already present into the pool, it is added. The + * int cache is updated and it returns the right index. + * + * @param float key + * @return int + */ +public int literalIndex(float key) { + //Retrieve the index from the cache + int index; + // lazy initialization for base type caches + // If it is null, initialize it, otherwise use it + if (floatCache == null) { + floatCache = new FloatCache(FLOAT_INITIAL_SIZE); + } + if ((index = floatCache.get(key)) < 0) { + index = floatCache.put(key, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the float constant entry into the constant pool + // First add the tag + writeU1(FloatTag); + // Then add the 4 bytes representing the float + int temp = java.lang.Float.floatToIntBits(key); + for (int i = 0; i < 4; i++) { + try { + poolContent[currentOffset++] = (byte) (temp >>> (24 - i * 8)); + } catch (IndexOutOfBoundsException e) { //currentOffset has been ++ already (see the -1) + int length = poolContent.length; + System.arraycopy(poolContent, 0, (poolContent = new byte[length * 2 + CONSTANTPOOL_INITIAL_SIZE]), 0, length); + poolContent[currentOffset - 1] = (byte) (temp >>> (24 - i * 8)); + } + } + }; + return index; +} +/** + * This method returns the index into the constantPool corresponding to the int + * value. If the int is not already present into the pool, it is added. The + * int cache is updated and it returns the right index. + * + * @param int key + * @return int + */ +public int literalIndex(int key) { + //Retrieve the index from the cache + int index; + // lazy initialization for base type caches + // If it is null, initialize it, otherwise use it + if (intCache == null) { + intCache = new IntegerCache(INT_INITIAL_SIZE); + } + if ((index = intCache.get(key)) < 0) { + index = intCache.put(key, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the integer constant entry into the constant pool + // First add the tag + writeU1(IntegerTag); + // Then add the 4 bytes representing the int + for (int i = 0; i < 4; i++) { + try { + poolContent[currentOffset++] = (byte) (key >>> (24 - i * 8)); + } catch (IndexOutOfBoundsException e) { //currentOffset has been ++ already (see the -1) + int length = poolContent.length; + System.arraycopy(poolContent, 0, (poolContent = new byte[length * 2 + CONSTANTPOOL_INITIAL_SIZE]), 0, length); + poolContent[currentOffset - 1] = (byte) (key >>> (24 - i * 8)); + } + } + }; + return index; +} +/** + * This method returns the index into the constantPool corresponding to the long + * value. If the long is not already present into the pool, it is added. The + * long cache is updated and it returns the right index. + * + * @param long key + * @return int + */ +public int literalIndex(long key) { + // Retrieve the index from the cache + // The long constant takes two indexes into the constant pool, but we only store + // the first index into the long table + int index; + // lazy initialization for base type caches + // If it is null, initialize it, otherwise use it + if (longCache == null) { + longCache = new LongCache(LONG_INITIAL_SIZE); + } + if ((index = longCache.get(key)) < 0) { + index = longCache.put(key, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + currentIndex++; // long value need an extra place into thwe constant pool + // Write the long into the constant pool + // First add the tag + writeU1(LongTag); + // Then add the 8 bytes representing the long + for (int i = 0; i < 8; i++) { + try { + poolContent[currentOffset++] = (byte) (key >>> (56 - (i << 3))); + } catch (IndexOutOfBoundsException e) { //currentOffset has been ++ already (see the -1) + int length = poolContent.length; + System.arraycopy(poolContent, 0, (poolContent = new byte[(length << 1) + CONSTANTPOOL_INITIAL_SIZE]), 0, length); + poolContent[currentOffset - 1] = (byte) (key >>> (56 - (i << 3))); + } + } + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param stringConstant java.lang.String + * @return int + */ +public int literalIndex(String stringConstant) { + int index; + char[] stringCharArray = stringConstant.toCharArray(); + if ((index = stringCache.get(stringCharArray)) < 0) { + // The entry doesn't exit yet + int stringIndex = literalIndex(stringCharArray); + index = stringCache.put(stringCharArray, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the tag first + writeU1(StringTag); + // Then the string index + writeU2(stringIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @param FieldBinding aFieldBinding + * @return int + */ +public int literalIndex(FieldBinding aFieldBinding) { + int index; + int nameAndTypeIndex; + int classIndex; + int indexWellKnownField; + if ((indexWellKnownField = indexOfWellKnownFields(aFieldBinding)) == -1) { + if ((index = fieldCache.get(aFieldBinding)) < 0) { + // The entry doesn't exit yet + classIndex = literalIndex(aFieldBinding.declaringClass); + nameAndTypeIndex = literalIndexForFields(literalIndex(aFieldBinding.name), literalIndex(aFieldBinding.type.signature()), aFieldBinding); + index = fieldCache.put(aFieldBinding, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + } else { + if ((index = wellKnownFields[indexWellKnownField]) == 0) { + // that field need to be inserted + classIndex = literalIndex(aFieldBinding.declaringClass); + nameAndTypeIndex = literalIndexForFields(literalIndex(aFieldBinding.name), literalIndex(aFieldBinding.type.signature()), aFieldBinding); + index = wellKnownFields[indexWellKnownField] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @param MethodBinding aMethodBinding + * @return int + */ +public int literalIndex(MethodBinding aMethodBinding) { + int index; + int nameAndTypeIndex; + int classIndex; + int indexWellKnownMethod; + if ((indexWellKnownMethod = indexOfWellKnownMethods(aMethodBinding)) == -1) { + if (aMethodBinding.declaringClass.isInterface()) { + // Lookinf into the interface method ref table + if ((index = interfaceMethodCache.get(aMethodBinding)) < 0) { + classIndex = literalIndex(aMethodBinding.declaringClass); + nameAndTypeIndex = literalIndexForMethods(literalIndex(aMethodBinding.constantPoolName()), literalIndex(aMethodBinding.signature()), aMethodBinding); + index = interfaceMethodCache.put(aMethodBinding, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the interface method ref constant into the constant pool + // First add the tag + writeU1(InterfaceMethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + } else { + // Lookinf into the method ref table + if ((index = methodCache.get(aMethodBinding)) < 0) { + classIndex = literalIndex(aMethodBinding.declaringClass); + nameAndTypeIndex = literalIndexForMethods(literalIndex(aMethodBinding.constantPoolName()), literalIndex(aMethodBinding.signature()), aMethodBinding); + index = methodCache.put(aMethodBinding, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + } + } else { + // This is a well known method + if ((index = wellKnownMethods[indexWellKnownMethod]) == 0) { + // this methods was not inserted yet + if (aMethodBinding.declaringClass.isInterface()) { + // Lookinf into the interface method ref table + classIndex = literalIndex(aMethodBinding.declaringClass); + nameAndTypeIndex = literalIndexForMethods(literalIndex(aMethodBinding.constantPoolName()), literalIndex(aMethodBinding.signature()), aMethodBinding); + index = wellKnownMethods[indexWellKnownMethod] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the interface method ref constant into the constant pool + // First add the tag + writeU1(InterfaceMethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } else { + // Lookinf into the method ref table + classIndex = literalIndex(aMethodBinding.declaringClass); + nameAndTypeIndex = literalIndexForMethods(literalIndex(aMethodBinding.constantPoolName()), literalIndex(aMethodBinding.signature()), aMethodBinding); + index = wellKnownMethods[indexWellKnownMethod] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + } + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndex(TypeBinding aTypeBinding) { + int index; + int nameIndex; + int indexWellKnownType; + if ((indexWellKnownType = indexOfWellKnownTypes(aTypeBinding)) == -1) { + if ((index = classCache.get(aTypeBinding)) < 0) { + // The entry doesn't exit yet + nameIndex = literalIndex(aTypeBinding.constantPoolName()); + index = classCache.put(aTypeBinding, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + } else { + if ((index = wellKnownTypes[indexWellKnownType]) == 0) { + // Need to insert that binding + nameIndex = literalIndex(aTypeBinding.constantPoolName()); + index = wellKnownTypes[indexWellKnownType] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + } + return index; +} +/** + * This method returns the index into the constantPool corresponding + * nameAndType constant with nameIndex, typeIndex. + * + * @param int nameIndex + * @param int nameIndex + * @param org.eclipse.jdt.internal.compiler.lookup.FieldBinding a FieldBinding + * @return int + */ +public int literalIndexForFields(int nameIndex, int typeIndex, FieldBinding key) { + int index; + int indexOfWellKnownFieldNameAndType; + if ((indexOfWellKnownFieldNameAndType = indexOfWellKnownFieldNameAndType(key)) == -1) { + // check if the entry already exists + if ((index = nameAndTypeCacheForFields.get(key)) == -1) { + // The entry doesn't exit yet + index = nameAndTypeCacheForFields.put(key, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + } else { + if ((index = wellKnownFieldNameAndTypes[indexOfWellKnownFieldNameAndType]) == 0) { + index = wellKnownFieldNameAndTypes[indexOfWellKnownFieldNameAndType] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangBoolean() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_BOOLEAN_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangBooleanConstantPoolName); + index = wellKnownTypes[JAVA_LANG_BOOLEAN_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangBooleanTYPE() { + int index; + if ((index = wellKnownFields[TYPE_BOOLEAN_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangBoolean(); + if ((nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.TYPE); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature); + nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[TYPE_BOOLEAN_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangByte() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_BYTE_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangByteConstantPoolName); + index = wellKnownTypes[JAVA_LANG_BYTE_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangByteTYPE() { + int index; + if ((index = wellKnownFields[TYPE_BYTE_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangByte(); + if ((nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.TYPE); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature); + nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[TYPE_BYTE_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangCharacter() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_CHARACTER_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangCharacterConstantPoolName); + index = wellKnownTypes[JAVA_LANG_CHARACTER_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangCharacterTYPE() { + int index; + if ((index = wellKnownFields[TYPE_CHARACTER_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangCharacter(); + if ((nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.TYPE); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature); + nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[TYPE_CHARACTER_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangClass() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_CLASS_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangClassConstantPoolName); + index = wellKnownTypes[JAVA_LANG_CLASS_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangClassForName() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[FORNAME_CLASS_METHOD]) == 0) { + classIndex = literalIndexForJavaLangClass(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[FORNAME_CLASS_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.ForName); + int typeIndex = literalIndex(QualifiedNamesConstants.ForNameSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[FORNAME_CLASS_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[FORNAME_CLASS_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangClassGetConstructor() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[GETCONSTRUCTOR_CLASS_METHOD]) == 0) { + classIndex = literalIndexForJavaLangClass(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[GETCONSTRUCTOR_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.GetConstructor); + int typeIndex = literalIndex(QualifiedNamesConstants.GetConstructorSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[GETCONSTRUCTOR_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[GETCONSTRUCTOR_CLASS_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangClassDesiredAssertionStatus() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[DESIREDASSERTIONSTATUS_CLASS_METHOD]) == 0) { + classIndex = literalIndexForJavaLangClass(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[DESIREDASSERTIONSTATUS_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.DesiredAssertionStatus); + int typeIndex = literalIndex(QualifiedNamesConstants.DesiredAssertionStatusSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[DESIREDASSERTIONSTATUS_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[DESIREDASSERTIONSTATUS_CLASS_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangClassNotFoundException() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_CLASSNOTFOUNDEXCEPTION_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangClassNotFoundExceptionConstantPoolName); + index = wellKnownTypes[JAVA_LANG_CLASSNOTFOUNDEXCEPTION_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangDouble() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_DOUBLE_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangDoubleConstantPoolName); + index = wellKnownTypes[JAVA_LANG_DOUBLE_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangDoubleTYPE() { + int index; + if ((index = wellKnownFields[TYPE_DOUBLE_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangDouble(); + if ((nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.TYPE); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature); + nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[TYPE_DOUBLE_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangError() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_ERROR_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangErrorConstantPoolName); + index = wellKnownTypes[JAVA_LANG_ERROR_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangErrorConstructor() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[JAVALANGERROR_CONSTR_METHOD]) == 0) { + classIndex = literalIndexForJavaLangError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_STRING_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.StringConstructorSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_STRING_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[JAVALANGERROR_CONSTR_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +public int literalIndexForJavaLangException() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_EXCEPTION_TYPE]) == 0) { + // The entry doesn't exit yet + int nameIndex = literalIndex(QualifiedNamesConstants.JavaLangExceptionConstantPoolName); + index = wellKnownTypes[JAVA_LANG_EXCEPTION_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangFloat() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_FLOAT_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangFloatConstantPoolName); + index = wellKnownTypes[JAVA_LANG_FLOAT_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangFloatTYPE() { + int index; + if ((index = wellKnownFields[TYPE_FLOAT_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangFloat(); + if ((nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.TYPE); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature); + nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[TYPE_FLOAT_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangInteger() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_INTEGER_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangIntegerConstantPoolName); + index = wellKnownTypes[JAVA_LANG_INTEGER_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangIntegerTYPE() { + int index; + if ((index = wellKnownFields[TYPE_INTEGER_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangInteger(); + if ((nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.TYPE); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature); + nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[TYPE_INTEGER_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangLong() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_LONG_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangLongConstantPoolName); + index = wellKnownTypes[JAVA_LANG_LONG_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangLongTYPE() { + int index; + if ((index = wellKnownFields[TYPE_LONG_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangLong(); + if ((nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.TYPE); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature); + nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[TYPE_LONG_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangNoClassDefFoundError() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_NOCLASSDEFFOUNDERROR_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangNoClassDefFoundErrorConstantPoolName); + index = wellKnownTypes[JAVA_LANG_NOCLASSDEFFOUNDERROR_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} + +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangAssertionError() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_ASSERTIONERROR_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangAssertionErrorConstantPoolName); + index = wellKnownTypes[JAVA_LANG_ASSERTIONERROR_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} + +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangAssertionErrorConstructor(int typeBindingID) { + int index = 0; + int nameAndTypeIndex = 0; + int classIndex = 0; + switch (typeBindingID) { + case T_int : + case T_byte : + case T_short : + if ((index = wellKnownMethods[ASSERTIONERROR_CONSTR_INT_METHOD]) == 0) { + classIndex = literalIndexForJavaLangAssertionError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_INT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.AssertionErrorIntConstrSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_INT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[ASSERTIONERROR_CONSTR_INT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_long : + if ((index = wellKnownMethods[ASSERTIONERROR_CONSTR_LONG_METHOD]) == 0) { + classIndex = literalIndexForJavaLangAssertionError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_LONG_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.AssertionErrorLongConstrSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_LONG_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[ASSERTIONERROR_CONSTR_LONG_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_float : + if ((index = wellKnownMethods[ASSERTIONERROR_CONSTR_FLOAT_METHOD]) == 0) { + classIndex = literalIndexForJavaLangAssertionError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_FLOAT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.AssertionErrorFloatConstrSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_FLOAT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[ASSERTIONERROR_CONSTR_FLOAT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_double : + if ((index = wellKnownMethods[ASSERTIONERROR_CONSTR_DOUBLE_METHOD]) == 0) { + classIndex = literalIndexForJavaLangAssertionError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_DOUBLE_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.AssertionErrorDoubleConstrSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_DOUBLE_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[ASSERTIONERROR_CONSTR_DOUBLE_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_char : + if ((index = wellKnownMethods[ASSERTIONERROR_CONSTR_CHAR_METHOD]) == 0) { + classIndex = literalIndexForJavaLangAssertionError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_CHAR_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.AssertionErrorCharConstrSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_CHAR_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[ASSERTIONERROR_CONSTR_CHAR_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_boolean : + if ((index = wellKnownMethods[ASSERTIONERROR_CONSTR_BOOLEAN_METHOD]) == 0) { + classIndex = literalIndexForJavaLangAssertionError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_BOOLEAN_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.AssertionErrorBooleanConstrSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_BOOLEAN_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[ASSERTIONERROR_CONSTR_BOOLEAN_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + //case T_Object : + //case T_String : + //case T_null : + default : + if ((index = wellKnownMethods[ASSERTIONERROR_CONSTR_OBJECT_METHOD]) == 0) { + classIndex = literalIndexForJavaLangAssertionError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_OBJECT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.AssertionErrorObjectConstrSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_OBJECT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[ASSERTIONERROR_CONSTR_OBJECT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + } + return index; +} + +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangAssertionErrorDefaultConstructor() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[ASSERTIONERROR_DEFAULT_CONSTR_METHOD]) == 0) { + classIndex = literalIndexForJavaLangAssertionError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[DEFAULT_CONSTR_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.DefaultConstructorSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[DEFAULT_CONSTR_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[ASSERTIONERROR_DEFAULT_CONSTR_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} + + +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangNoClassDefFoundErrorStringConstructor() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[NOCLASSDEFFOUNDERROR_CONSTR_METHOD]) == 0) { + classIndex = literalIndexForJavaLangNoClassDefFoundError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_STRING_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.StringConstructorSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_STRING_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[NOCLASSDEFFOUNDERROR_CONSTR_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangObject() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_OBJECT_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangObjectConstantPoolName); + index = wellKnownTypes[JAVA_LANG_OBJECT_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangReflectConstructor() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_REFLECT_CONSTRUCTOR_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangReflectConstructor); + index = wellKnownTypes[JAVA_LANG_REFLECT_CONSTRUCTOR_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +public int literalIndexForJavaLangReflectConstructorNewInstance() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[NEWINSTANCE_CONSTRUCTOR_METHOD]) == 0) { + classIndex = literalIndexForJavaLangReflectConstructor(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[NEWINSTANCE_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.NewInstance); + int typeIndex = literalIndex(QualifiedNamesConstants.NewInstanceSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[NEWINSTANCE_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[NEWINSTANCE_CONSTRUCTOR_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangShort() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_SHORT_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangShortConstantPoolName); + index = wellKnownTypes[JAVA_LANG_SHORT_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangShortTYPE() { + int index; + if ((index = wellKnownFields[TYPE_SHORT_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangShort(); + if ((nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.TYPE); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature); + nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[TYPE_SHORT_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangString() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_STRING_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangStringConstantPoolName); + index = wellKnownTypes[JAVA_LANG_STRING_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangStringBuffer() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_STRINGBUFFER_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangStringBufferConstantPoolName); + index = wellKnownTypes[JAVA_LANG_STRINGBUFFER_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangStringBufferAppend(int typeID) { + int index = 0; + int nameAndTypeIndex = 0; + int classIndex = 0; + switch (typeID) { + case T_int : + case T_byte : + case T_short : + if ((index = wellKnownMethods[APPEND_INT_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_INT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Append); + int typeIndex = literalIndex(QualifiedNamesConstants.AppendIntSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_INT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[APPEND_INT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_long : + if ((index = wellKnownMethods[APPEND_LONG_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_LONG_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Append); + int typeIndex = literalIndex(QualifiedNamesConstants.AppendLongSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_LONG_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[APPEND_LONG_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_float : + if ((index = wellKnownMethods[APPEND_FLOAT_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_FLOAT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Append); + int typeIndex = literalIndex(QualifiedNamesConstants.AppendFloatSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_FLOAT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[APPEND_FLOAT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_double : + if ((index = wellKnownMethods[APPEND_DOUBLE_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_DOUBLE_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Append); + int typeIndex = literalIndex(QualifiedNamesConstants.AppendDoubleSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_DOUBLE_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[APPEND_DOUBLE_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_char : + if ((index = wellKnownMethods[APPEND_CHAR_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_CHAR_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Append); + int typeIndex = literalIndex(QualifiedNamesConstants.AppendCharSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_CHAR_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[APPEND_CHAR_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_boolean : + if ((index = wellKnownMethods[APPEND_BOOLEAN_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_BOOLEAN_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Append); + int typeIndex = literalIndex(QualifiedNamesConstants.AppendBooleanSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_BOOLEAN_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[APPEND_BOOLEAN_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_Object : + if ((index = wellKnownMethods[APPEND_OBJECT_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_OBJECT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Append); + int typeIndex = literalIndex(QualifiedNamesConstants.AppendObjectSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_OBJECT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[APPEND_OBJECT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_String : + case T_null : + if ((index = wellKnownMethods[APPEND_STRING_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_STRING_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Append); + int typeIndex = literalIndex(QualifiedNamesConstants.AppendStringSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_STRING_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[APPEND_STRING_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangStringBufferConstructor() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[STRINGBUFFER_STRING_CONSTR_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_STRING_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.StringConstructorSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_STRING_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[STRINGBUFFER_STRING_CONSTR_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangStringBufferDefaultConstructor() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[STRINGBUFFER_DEFAULT_CONSTR_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[DEFAULT_CONSTR_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.DefaultConstructorSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[DEFAULT_CONSTR_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[STRINGBUFFER_DEFAULT_CONSTR_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangStringBufferToString() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[STRINGBUFFER_TOSTRING_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[TOSTRING_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.ToString); + int typeIndex = literalIndex(QualifiedNamesConstants.ToStringSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[TOSTRING_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[STRINGBUFFER_TOSTRING_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangStringIntern() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[STRING_INTERN_METHOD]) == 0) { + classIndex = literalIndexForJavaLangString(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[INTERN_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Intern); + int typeIndex = literalIndex(QualifiedNamesConstants.InternSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[INTERN_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[STRING_INTERN_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangStringValueOf(int typeID) { + int index = 0; + int nameAndTypeIndex = 0; + int classIndex = literalIndexForJavaLangString(); + switch (typeID) { + case T_int : + case T_byte : + case T_short : + if ((index = wellKnownMethods[VALUEOF_INT_METHOD]) == 0) { + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_INT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf); + int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfIntSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_INT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[VALUEOF_INT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_long : + if ((index = wellKnownMethods[VALUEOF_LONG_METHOD]) == 0) { + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_LONG_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf); + int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfLongSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_LONG_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[VALUEOF_LONG_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_float : + if ((index = wellKnownMethods[VALUEOF_FLOAT_METHOD]) == 0) { + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_FLOAT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf); + int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfFloatSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_FLOAT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[VALUEOF_FLOAT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_double : + if ((index = wellKnownMethods[VALUEOF_DOUBLE_METHOD]) == 0) { + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_DOUBLE_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf); + int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfDoubleSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_DOUBLE_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[VALUEOF_DOUBLE_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_char : + if ((index = wellKnownMethods[VALUEOF_CHAR_METHOD]) == 0) { + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_CHAR_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf); + int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfCharSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_CHAR_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[VALUEOF_CHAR_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_boolean : + if ((index = wellKnownMethods[VALUEOF_BOOLEAN_METHOD]) == 0) { + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_BOOLEAN_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf); + int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfBooleanSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_BOOLEAN_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[VALUEOF_BOOLEAN_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_Object : + if ((index = wellKnownMethods[VALUEOF_OBJECT_METHOD]) == 0) { + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_OBJECT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf); + int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfObjectSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_OBJECT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[VALUEOF_OBJECT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangSystem() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_SYSTEM_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangSystemConstantPoolName); + index = wellKnownTypes[JAVA_LANG_SYSTEM_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangSystemExitInt() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[SYSTEM_EXIT_METHOD]) == 0) { + classIndex = literalIndexForJavaLangSystem(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[EXIT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Exit); + int typeIndex = literalIndex(QualifiedNamesConstants.ExitIntSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[EXIT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[SYSTEM_EXIT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangSystemOut() { + int index; + if ((index = wellKnownFields[OUT_SYSTEM_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangSystem(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[OUT_SYSTEM_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Out); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaIoPrintStreamSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[OUT_SYSTEM_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[OUT_SYSTEM_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangThrowable() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_THROWABLE_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangThrowableConstantPoolName); + index = wellKnownTypes[JAVA_LANG_THROWABLE_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangThrowableGetMessage() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[THROWABLE_GETMESSAGE_METHOD]) == 0) { + classIndex = literalIndexForJavaLangThrowable(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[GETMESSAGE_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.GetMessage); + int typeIndex = literalIndex(QualifiedNamesConstants.GetMessageSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[GETMESSAGE_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[THROWABLE_GETMESSAGE_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param TypeBinding aTypeBinding + * @return int + */ +public int literalIndexForJavaLangVoid() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_VOID_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangVoidConstantPoolName); + index = wellKnownTypes[JAVA_LANG_VOID_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangVoidTYPE() { + int index; + if ((index = wellKnownFields[TYPE_VOID_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangVoid(); + if ((nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.TYPE); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature); + nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[TYPE_VOID_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param char[] stringName + * @return int + */ +public int literalIndexForLdc(char[] stringCharArray) { + int index; + if ((index = stringCache.get(stringCharArray)) < 0) { + int stringIndex; + // The entry doesn't exit yet + if ((stringIndex = UTF8Cache.get(stringCharArray)) < 0) { + // The entry doesn't exit yet + // Write the tag first + writeU1(Utf8Tag); + // Then the size of the stringName array + int savedCurrentOffset = currentOffset; + if (currentOffset + 2 >= poolContent.length) { + // we need to resize the poolContent array because we won't have + // enough space to write the length + int length = poolContent.length; + System.arraycopy(poolContent, 0, (poolContent = new byte[length + CONSTANTPOOL_GROW_SIZE]), 0, length); + } + currentOffset += 2; + int length = 0; + for (int i = 0; i < stringCharArray.length; i++) { + char current = stringCharArray[i]; + if ((current >= 0x0001) && (current <= 0x007F)) { + // we only need one byte: ASCII table + writeU1(current); + length++; + } else + if (current > 0x07FF) { + // we need 3 bytes + length += 3; + writeU1(0xE0 | ((current >> 12) & 0x0F)); // 0xE0 = 1110 0000 + writeU1(0x80 | ((current >> 6) & 0x3F)); // 0x80 = 1000 0000 + writeU1(0x80 | (current & 0x3F)); // 0x80 = 1000 0000 + } else { + // we can be 0 or between 0x0080 and 0x07FF + // In that case we only need 2 bytes + length += 2; + writeU1(0xC0 | ((current >> 6) & 0x1F)); // 0xC0 = 1100 0000 + writeU1(0x80 | (current & 0x3F)); // 0x80 = 1000 0000 + } + } + if (length >= 65535) { + currentOffset = savedCurrentOffset - 1; + return -1; + } + stringIndex = UTF8Cache.put(stringCharArray, currentIndex++); + // Now we know the length that we have to write in the constant pool + // we use savedCurrentOffset to do that + if (length > 65535) { + return 0; + } + poolContent[savedCurrentOffset] = (byte) (length >> 8); + poolContent[savedCurrentOffset + 1] = (byte) length; + } + index = stringCache.put(stringCharArray, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the tag first + writeU1(StringTag); + // Then the string index + writeU2(stringIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding + * nameAndType constant with nameIndex, typeIndex. + * + * @param int nameIndex + * @param int nameIndex + * @param org.eclipse.jdt.internal.compiler.lookup.MethodBinding a methodBinding + * @return int + */ +public int literalIndexForMethods(int nameIndex, int typeIndex, MethodBinding key) { + int index; + int indexOfWellKnownMethodNameAndType; + if ((indexOfWellKnownMethodNameAndType = indexOfWellKnownMethodNameAndType(key)) == -1) { + // check if the entry exists + if ((index = nameAndTypeCacheForMethods.get(key)) == -1) { + // The entry doesn't exit yet + index = nameAndTypeCacheForMethods.put(key, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + } else { + if ((index = wellKnownMethodNameAndTypes[indexOfWellKnownMethodNameAndType]) == 0) { + index = wellKnownMethodNameAndTypes[indexOfWellKnownMethodNameAndType] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangObjectGetClass() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[GETCLASS_OBJECT_METHOD]) == 0) { + classIndex = literalIndexForJavaLangObject(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[GETCLASS_OBJECT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.GetClass); + int typeIndex = literalIndex(QualifiedNamesConstants.GetClassSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[GETCLASS_OBJECT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[GETCLASS_OBJECT_METHOD] = currentIndex++; + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method is used to clean the receiver in case of a clinit header is generated, but the + * clinit has no code. + * This implementation assumes that the clinit is the first method to be generated. + * @see org.eclipse.jdt.internal.compiler.ast.TypeDeclaration#addClinit() + */ +public void resetForClinit(int constantPoolIndex, int constantPoolOffset) { + currentIndex = constantPoolIndex; + currentOffset = constantPoolOffset; + if (UTF8Cache.get(AttributeNamesConstants.CodeName) >= constantPoolIndex) { + UTF8Cache.remove(AttributeNamesConstants.CodeName); + } + if (UTF8Cache.get(QualifiedNamesConstants.ClinitSignature) >= constantPoolIndex) { + UTF8Cache.remove(QualifiedNamesConstants.ClinitSignature); + } + if (UTF8Cache.get(QualifiedNamesConstants.Clinit) >= constantPoolIndex) { + UTF8Cache.remove(QualifiedNamesConstants.Clinit); + } +} +/** + * Write a unsigned byte into the byte array + * + * @param int The value to write into the byte array + */ +protected final void writeU1(int value) { + try { + poolContent[currentOffset++] = (byte) value; + } catch (IndexOutOfBoundsException e) { + //currentOffset has been ++ already (see the -1) + int length = poolContent.length; + System.arraycopy(poolContent, 0, (poolContent = new byte[length + CONSTANTPOOL_GROW_SIZE]), 0, length); + poolContent[currentOffset - 1] = (byte) value; + } +} +/** + * Write a unsigned byte into the byte array + * + * @param int The value to write into the byte array + */ +protected final void writeU2(int value) { + //first byte + try { + poolContent[currentOffset++] = (byte) (value >> 8); + } catch (IndexOutOfBoundsException e) { + //currentOffset has been ++ already (see the -1) + int length = poolContent.length; + System.arraycopy(poolContent, 0, (poolContent = new byte[length + CONSTANTPOOL_GROW_SIZE]), 0, length); + poolContent[currentOffset - 1] = (byte) (value >> 8); + } + try { + poolContent[currentOffset++] = (byte) value; + } catch (IndexOutOfBoundsException e) { + //currentOffset has been ++ already (see the -1) + int length = poolContent.length; + System.arraycopy(poolContent, 0, (poolContent = new byte[length + CONSTANTPOOL_GROW_SIZE]), 0, length); + poolContent[currentOffset - 1] = (byte) value; + } +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/DoubleCache.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/DoubleCache.java new file mode 100644 index 0000000..4eb3ee2 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/DoubleCache.java @@ -0,0 +1,138 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.codegen; + +public class DoubleCache { + private double keyTable[]; + private int valueTable[]; + private int elementSize; +/** + * Constructs a new, empty hashtable. A default capacity and + * load factor is used. Note that the hashtable will automatically + * grow when it gets full. + */ +public DoubleCache() { + this(13); +} +/** + * Constructs a new, empty hashtable with the specified initial + * capacity. + * @param initialCapacity int + * the initial number of buckets + */ +public DoubleCache(int initialCapacity) { + elementSize = 0; + keyTable = new double[initialCapacity]; + valueTable = new int[initialCapacity]; +} +/** + * Clears the hash table so that it has no more elements in it. + */ +public void clear() { + for (int i = keyTable.length; --i >= 0;) { + keyTable[i] = 0.0; + valueTable[i] = 0; + } + elementSize = 0; +} +/** Returns true if the collection contains an element for the key. + * + * @param key double the key that we are looking for + * @return boolean + */ +public boolean containsKey(double key) { + if (key == 0.0) { + for (int i = 0, max = elementSize; i < max; i++) { + if (keyTable[i] == 0.0) { + long value1 = Double.doubleToLongBits(key); + long value2 = Double.doubleToLongBits(keyTable[i]); + if (value1 == -9223372036854775808L && value2 == -9223372036854775808L) + return true; + if (value1 == 0 && value2 == 0) + return true; + } + } + } else { + for (int i = 0, max = elementSize; i < max; i++) { + if (keyTable[i] == key) { + return true; + } + } + } + return false; +} +/** Gets the object associated with the specified key in the + * hashtable. + * @param key double the specified key + * @return int the element for the key or -1 if the key is not + * defined in the hash table. + */ +public int get(double key) { + if (key == 0.0) { + for (int i = 0, max = elementSize; i < max; i++) { + if (keyTable[i] == 0.0) { + long value1 = Double.doubleToLongBits(key); + long value2 = Double.doubleToLongBits(keyTable[i]); + if (value1 == -9223372036854775808L && value2 == -9223372036854775808L) + return valueTable[i]; + if (value1 == 0 && value2 == 0) + return valueTable[i]; + } + } + } else { + for (int i = 0, max = elementSize; i < max; i++) { + if (keyTable[i] == key) { + return valueTable[i]; + } + } + } + return -1; +} +/** + * Puts the specified element into the hashtable, using the specified + * key. The element may be retrieved by doing a get() with the same key. + * + * @param key double the specified key in the hashtable + * @param value int the specified element + * @return int value + */ +public int put(double key, int value) { + if (elementSize == keyTable.length) { + // resize + System.arraycopy(keyTable, 0, (keyTable = new double[elementSize * 2]), 0, elementSize); + System.arraycopy(valueTable, 0, (valueTable = new int[elementSize * 2]), 0, elementSize); + } + keyTable[elementSize] = key; + valueTable[elementSize] = value; + elementSize++; + return value; +} +/** + * Converts to a rather lengthy String. + * + * @return String the ascii representation of the receiver + */ +public String toString() { + int max = elementSize; + StringBuffer buf = new StringBuffer(); + buf.append("{"); //$NON-NLS-1$ + for (int i = 0; i < max; ++i) { + if ((keyTable[i] != 0) || ((keyTable[i] == 0) &&(valueTable[i] != 0))) { + buf.append(keyTable[i]).append("->").append(valueTable[i]); //$NON-NLS-1$ + } + if (i < max) { + buf.append(", "); //$NON-NLS-1$ + } + } + buf.append("}"); //$NON-NLS-1$ + return buf.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/ExceptionLabel.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/ExceptionLabel.java new file mode 100644 index 0000000..cc75cd2 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/ExceptionLabel.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.codegen; + +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; + +public class ExceptionLabel extends Label { + public int start = POS_NOT_SET; + public int end = POS_NOT_SET; + public TypeBinding exceptionType; +public ExceptionLabel(CodeStream codeStream, TypeBinding exceptionType) { + super(codeStream); + this.exceptionType = exceptionType; + this.start = codeStream.position; +} +public boolean isStandardLabel(){ + return false; +} +public void place() { + // register the handler inside the codeStream then normal place + codeStream.registerExceptionHandler(this); + super.place(); + +} +public void placeEnd() { + end = codeStream.position; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/FieldNameAndTypeCache.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/FieldNameAndTypeCache.java new file mode 100644 index 0000000..9d65aa2 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/FieldNameAndTypeCache.java @@ -0,0 +1,161 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.codegen; + +import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class FieldNameAndTypeCache { + public FieldBinding keyTable[]; + public int valueTable[]; + int elementSize; + int threshold; +/** + * Constructs a new, empty hashtable. A default capacity is used. + * Note that the hashtable will automatically grow when it gets full. + */ +public FieldNameAndTypeCache() { + this(13); +} +/** + * Constructs a new, empty hashtable with the specified initial + * capacity. + * @param initialCapacity int + * the initial number of buckets + */ +public FieldNameAndTypeCache(int initialCapacity) { + this.elementSize = 0; + this.threshold = (int) (initialCapacity * 0.66f); + this.keyTable = new FieldBinding[initialCapacity]; + this.valueTable = new int[initialCapacity]; +} +/** + * Clears the hash table so that it has no more elements in it. + */ +public void clear() { + for (int i = keyTable.length; --i >= 0;) { + keyTable[i] = null; + valueTable[i] = 0; + } + elementSize = 0; +} +/** Returns true if the collection contains an element for the key. + * + * @param char[] key the key that we are looking for + * @return boolean + */ +public boolean containsKey(FieldBinding key) { + int index = hashCode(key); + while (keyTable[index] != null) { + if (equalsForNameAndType(keyTable[index], key)) + return true; + index = (index + 1) % keyTable.length; + } + return false; +} +/** + * Return true if the two field binding are consider like equals. + */ +public boolean equalsForNameAndType(FieldBinding field1, FieldBinding field2) { + return ((field1.type == field2.type) && CharOperation.equals(field1.name, field2.name)); +} +/** Gets the object associated with the specified key in the + * hashtable. + * @param key char[] the specified key + * @return int the element for the key or -1 if the key is not + * defined in the hash table. + */ +public int get(FieldBinding key) { + int index = hashCode(key); + while (keyTable[index] != null) { + if (equalsForNameAndType(keyTable[index], key)) + return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return -1; +} +/** + * Return the hashcode for the key parameter + * + * @param key org.eclipse.jdt.internal.compiler.lookup.MethodBinding + * @return int + */ +public int hashCode(FieldBinding key) { + return ((CharOperation.hashCode(key.name) + key.type.hashCode()) & 0x7FFFFFFF) % keyTable.length; +} +/** + * Puts the specified element into the hashtable, using the specified + * key. The element may be retrieved by doing a get() with the same key. + * The key and the element cannot be null. + * + * @param key Object the specified key in the hashtable + * @param value int the specified element + * @return int the old value of the key, or -1 if it did not have one. + */ +public int put(FieldBinding key, int value) { + int index = hashCode(key); + while (keyTable[index] != null) { + if (equalsForNameAndType(keyTable[index], key)) + return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) + rehash(); + return value; +} +/** + * Rehashes the content of the table into a bigger table. + * This method is called automatically when the hashtable's + * size exceeds the threshold. + */ +private void rehash() { + FieldNameAndTypeCache newHashtable = new FieldNameAndTypeCache(keyTable.length * 2); + for (int i = keyTable.length; --i >= 0;) + if (keyTable[i] != null) + newHashtable.put(keyTable[i], valueTable[i]); + + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; +} +/** + * Returns the number of elements contained in the hashtable. + * + * @return int The size of the table + */ +public int size() { + return elementSize; +} +/** + * Converts to a rather lengthy String. + * + * @return String the ascii representation of the receiver + */ +public String toString() { + int max = size(); + StringBuffer buf = new StringBuffer(); + buf.append("{"); //$NON-NLS-1$ + for (int i = 0; i < max; ++i) { + if (keyTable[i] != null) { + buf.append(keyTable[i]).append("->").append(valueTable[i]); //$NON-NLS-1$ + } + if (i < max) { + buf.append(", "); //$NON-NLS-1$ + } + } + buf.append("}"); //$NON-NLS-1$ + return buf.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/FloatCache.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/FloatCache.java new file mode 100644 index 0000000..8c57c77 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/FloatCache.java @@ -0,0 +1,138 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.codegen; + +public class FloatCache { + private float keyTable[]; + private int valueTable[]; + private int elementSize; +/** + * Constructs a new, empty hashtable. A default capacity and + * load factor is used. Note that the hashtable will automatically + * grow when it gets full. + */ +public FloatCache() { + this(13); +} +/** + * Constructs a new, empty hashtable with the specified initial + * capacity. + * @param initialCapacity int + * the initial number of buckets + */ +public FloatCache(int initialCapacity) { + elementSize = 0; + keyTable = new float[initialCapacity]; + valueTable = new int[initialCapacity]; +} +/** + * Clears the hash table so that it has no more elements in it. + */ +public void clear() { + for (int i = keyTable.length; --i >= 0;) { + keyTable[i] = 0.0f; + valueTable[i] = 0; + } + elementSize = 0; +} +/** Returns true if the collection contains an element for the key. + * + * @param key float the key that we are looking for + * @return boolean + */ +public boolean containsKey(float key) { + if (key == 0.0f) { + for (int i = 0, max = elementSize; i < max; i++) { + if (keyTable[i] == 0.0f) { + int value1 = Float.floatToIntBits(key); + int value2 = Float.floatToIntBits(keyTable[i]); + if (value1 == -2147483648 && value2 == -2147483648) + return true; + if (value1 == 0 && value2 == 0) + return true; + } + } + } else { + for (int i = 0, max = elementSize; i < max; i++) { + if (keyTable[i] == key) { + return true; + } + } + } + return false; +} +/** Gets the object associated with the specified key in the + * hashtable. + * @param key float the specified key + * @return int the element for the key or -1 if the key is not + * defined in the hash table. + */ +public int get(float key) { + if (key == 0.0f) { + for (int i = 0, max = elementSize; i < max; i++) { + if (keyTable[i] == 0.0f) { + int value1 = Float.floatToIntBits(key); + int value2 = Float.floatToIntBits(keyTable[i]); + if (value1 == -2147483648 && value2 == -2147483648) + return valueTable[i]; + if (value1 == 0 && value2 == 0) + return valueTable[i]; + } + } + } else { + for (int i = 0, max = elementSize; i < max; i++) { + if (keyTable[i] == key) { + return valueTable[i]; + } + } + } + return -1; +} +/** + * Puts the specified element into the hashtable, using the specified + * key. The element may be retrieved by doing a get() with the same key. + * + * @param key float the specified key in the hashtable + * @param value int the specified element + * @return int value + */ +public int put(float key, int value) { + if (elementSize == keyTable.length) { + // resize + System.arraycopy(keyTable, 0, (keyTable = new float[elementSize * 2]), 0, elementSize); + System.arraycopy(valueTable, 0, (valueTable = new int[elementSize * 2]), 0, elementSize); + } + keyTable[elementSize] = key; + valueTable[elementSize] = value; + elementSize++; + return value; +} +/** + * Converts to a rather lengthy String. + * + * @return String the ascii representation of the receiver + */ +public String toString() { + int max = elementSize; + StringBuffer buf = new StringBuffer(); + buf.append("{"); //$NON-NLS-1$ + for (int i = 0; i < max; ++i) { + if ((keyTable[i] != 0) || ((keyTable[i] == 0) && (valueTable[i] != 0))) { + buf.append(keyTable[i]).append("->").append(valueTable[i]); //$NON-NLS-1$ + } + if (i < max) { + buf.append(", "); //$NON-NLS-1$ + } + } + buf.append("}"); //$NON-NLS-1$ + return buf.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/IntegerCache.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/IntegerCache.java new file mode 100644 index 0000000..824d3eb --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/IntegerCache.java @@ -0,0 +1,155 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.codegen; + +public class IntegerCache { + public int keyTable[]; + public int valueTable[]; + int elementSize; + int threshold; +/** + * Constructs a new, empty hashtable. A default capacity and + * load factor is used. Note that the hashtable will automatically + * grow when it gets full. + */ +public IntegerCache() { + this(13); +} +/** + * Constructs a new, empty hashtable with the specified initial + * capacity. + * @param initialCapacity int + * the initial number of buckets + */ +public IntegerCache(int initialCapacity) { + elementSize = 0; + threshold = (int) (initialCapacity * 0.66); + keyTable = new int[initialCapacity]; + valueTable = new int[initialCapacity]; +} +/** + * Clears the hash table so that it has no more elements in it. + */ +public void clear() { + for (int i = keyTable.length; --i >= 0;) { + keyTable[i] = 0; + valueTable[i] = 0; + } + elementSize = 0; +} +/** Returns true if the collection contains an element for the key. + * + * @param key double the key that we are looking for + * @return boolean + */ +public boolean containsKey(int key) { + int index = hash(key); + while ((keyTable[index] != 0) || ((keyTable[index] == 0) &&(valueTable[index] != 0))) { + if (keyTable[index] == key) + return true; + index = (index + 1) % keyTable.length; + } + return false; +} +/** Gets the object associated with the specified key in the + * hashtable. + * @param key double the specified key + * @return int the element for the key or -1 if the key is not + * defined in the hash table. + */ +public int get(int key) { + int index = hash(key); + while ((keyTable[index] != 0) || ((keyTable[index] == 0) &&(valueTable[index] != 0))) { + if (keyTable[index] == key) + return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return -1; +} +/** + * Return a hashcode for the value of the key parameter. + * @param key int + * @return int the hash code corresponding to the key value + */ +public int hash(int key) { + return (key & 0x7FFFFFFF) % keyTable.length; +} +/** + * Puts the specified element into the hashtable, using the specified + * key. The element may be retrieved by doing a get() with the same key. + * + * @param key int the specified key in the hashtable + * @param value int the specified element + * @return int value + */ +public int put(int key, int value) { + int index = hash(key); + while ((keyTable[index] != 0) || ((keyTable[index] == 0) && (valueTable[index] != 0))) { + if (keyTable[index] == key) + return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) { + rehash(); + } + return value; +} +/** + * Rehashes the content of the table into a bigger table. + * This method is called automatically when the hashtable's + * size exceeds the threshold. + */ +private void rehash() { + IntegerCache newHashtable = new IntegerCache(keyTable.length * 2); + for (int i = keyTable.length; --i >= 0;) { + int key = keyTable[i]; + int value = valueTable[i]; + if ((key != 0) || ((key == 0) && (value != 0))) { + newHashtable.put(key, value); + } + } + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; +} +/** + * Returns the number of elements contained in the hashtable. + * + * @return int The size of the table + */ +public int size() { + return elementSize; +} +/** + * Converts to a rather lengthy String. + * + * @return String the ascii representation of the receiver + */ +public String toString() { + int max = size(); + StringBuffer buf = new StringBuffer(); + buf.append("{"); //$NON-NLS-1$ + for (int i = 0; i < max; ++i) { + if ((keyTable[i] != 0) || ((keyTable[i] == 0) && (valueTable[i] != 0))) { + buf.append(keyTable[i]).append("->").append(valueTable[i]); //$NON-NLS-1$ + } + if (i < max) { + buf.append(", "); //$NON-NLS-1$ + } + } + buf.append("}"); //$NON-NLS-1$ + return buf.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/Label.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/Label.java new file mode 100644 index 0000000..d75371e --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/Label.java @@ -0,0 +1,246 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.codegen; + +import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding; +import net.sourceforge.phpdt.internal.compiler.problem.AbortMethod; + +/** + * This type is a port of smalltalks JavaLabel + */ +public class Label { + public CodeStream codeStream; + final static int POS_NOT_SET = -1; + public int position = POS_NOT_SET; // position=POS_NOT_SET Then it's pos is not set. + public int[] forwardReferences = new int[10]; // Add an overflow check here. + public int forwardReferenceCount = 0; + private boolean isWide = false; +public Label() { +} +/** + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ +public Label(CodeStream codeStream) { + this.codeStream = codeStream; +} +/** + * Add a forward refrence for the array. + */ +void addForwardReference(int iPos) { + int length; + if (forwardReferenceCount >= (length = forwardReferences.length)) + System.arraycopy(forwardReferences, 0, (forwardReferences = new int[2*length]), 0, length); + forwardReferences[forwardReferenceCount++] = iPos; +} +/** + * Add a forward refrence for the array. + */ +public void appendForwardReferencesFrom(Label otherLabel) { + int otherCount = otherLabel.forwardReferenceCount; + if (otherCount == 0) return; + int length = forwardReferences.length; + int neededSpace = otherCount + forwardReferenceCount; + if (neededSpace >= length){ + System.arraycopy(forwardReferences, 0, (forwardReferences = new int[neededSpace]), 0, forwardReferenceCount); + } + // append other forward references at the end, so they will get updated as well + System.arraycopy(otherLabel.forwardReferences, 0, forwardReferences, forwardReferenceCount, otherCount); + forwardReferenceCount = neededSpace; +} +/* +* Put down a refernece to the array at the location in the codestream. +*/ +void branch() { + if (position == POS_NOT_SET) { + addForwardReference(codeStream.position); + // Leave two bytes free to generate the jump afterwards + codeStream.position += 2; + codeStream.classFileOffset += 2; + } else { //Position is set. Write it! + codeStream.writeSignedShort((short) (position - codeStream.position + 1)); + } +} +/* +* No support for wide branches yet +*/ +void branchWide() { + if (position == POS_NOT_SET) { + addForwardReference(codeStream.position); + // Leave 4 bytes free to generate the jump offset afterwards + isWide = true; + codeStream.position += 4; + codeStream.classFileOffset += 4; + } else { //Position is set. Write it! + codeStream.writeSignedWord(position - codeStream.position + 1); + } +} +/** + * @return boolean + */ +public boolean hasForwardReferences() { + return forwardReferenceCount != 0; +} +/* + * Some placed labels might be branching to a goto bytecode which we can optimize better. + */ +public void inlineForwardReferencesFromLabelsTargeting(int gotoLocation) { +/* + Code required to optimized unreachable gotos. + public boolean isBranchTarget(int location) { + Label[] labels = codeStream.labels; + for (int i = codeStream.countLabels - 1; i >= 0; i--){ + Label label = labels[i]; + if ((label.position == location) && label.isStandardLabel()){ + return true; + } + } + return false; + } + */ + + Label[] labels = codeStream.labels; + for (int i = codeStream.countLabels - 1; i >= 0; i--){ + Label label = labels[i]; + if ((label.position == gotoLocation) && label.isStandardLabel()){ + this.appendForwardReferencesFrom(label); + /* + Code required to optimized unreachable gotos. + label.position = POS_NOT_SET; + */ + } else { + break; // same target labels should be contiguous + } + } +} +public boolean isStandardLabel(){ + return true; +} +/* +* Place the label. If we have forward references resolve them. +*/ +public void place() { // Currently lacking wide support. + if (position == POS_NOT_SET) { + position = codeStream.position; + codeStream.addLabel(this); + int oldPosition = position; + boolean optimizedBranch = false; + // TURNED OFF since fail on 1F4IRD9 + if (forwardReferenceCount != 0) { + if (optimizedBranch = (forwardReferences[forwardReferenceCount - 1] + 2 == position) && (codeStream.bCodeStream[codeStream.classFileOffset - 3] == CodeStream.OPC_goto)) { + codeStream.position = (position -= 3); + codeStream.classFileOffset -= 3; + forwardReferenceCount--; + // also update the PCs in the related debug attributes + /** OLD CODE + int index = codeStream.pcToSourceMapSize - 1; + while ((index >= 0) && (codeStream.pcToSourceMap[index][1] == oldPosition)) { + codeStream.pcToSourceMap[index--][1] = position; + } + */ + // Beginning of new code + int index = codeStream.pcToSourceMapSize - 2; + if (codeStream.lastEntryPC == oldPosition) { + codeStream.lastEntryPC = position; + } + if ((index >= 0) && (codeStream.pcToSourceMap[index] == position)) { + codeStream.pcToSourceMapSize-=2; + } + // end of new code + if (codeStream.generateLocalVariableTableAttributes) { + LocalVariableBinding locals[] = codeStream.locals; + for (int i = 0, max = locals.length; i < max; i++) { + LocalVariableBinding local = locals[i]; + if ((local != null) && (local.initializationCount > 0)) { + if (local.initializationPCs[((local.initializationCount - 1) << 1) + 1] == oldPosition) { + // we want to prevent interval of size 0 to have a negative size. + // see PR 1GIRQLA: ITPJCORE:ALL - ClassFormatError for local variable attribute + local.initializationPCs[((local.initializationCount - 1) << 1) + 1] = position; + } + if (local.initializationPCs[(local.initializationCount - 1) << 1] == oldPosition) { + local.initializationPCs[(local.initializationCount - 1) << 1] = position; + } + } + } + } + } + } + for (int i = 0; i < forwardReferenceCount; i++) { + int offset = position - forwardReferences[i] + 1; + if (offset > 0x7FFF && !this.codeStream.wideMode) { + throw new AbortMethod(CodeStream.RESTART_IN_WIDE_MODE); + } + if (this.codeStream.wideMode) { + if (this.isWide) { + codeStream.writeSignedWord(forwardReferences[i], offset); + } else { + codeStream.writeSignedShort(forwardReferences[i], (short) offset); + } + } else { + codeStream.writeSignedShort(forwardReferences[i], (short) offset); + } + } + // For all labels placed at that position we check if we need to rewrite the jump + // offset. It is the case each time a label had a forward reference to the current position. + // Like we change the current position, we have to change the jump offset. See 1F4IRD9 for more details. + if (optimizedBranch) { + for (int i = 0; i < codeStream.countLabels; i++) { + Label label = codeStream.labels[i]; + if (oldPosition == label.position) { + label.position = position; + if (label instanceof CaseLabel) { + int offset = position - ((CaseLabel) label).instructionPosition; + for (int j = 0; j < label.forwardReferenceCount; j++) { + int forwardPosition = label.forwardReferences[j]; + codeStream.writeSignedWord(forwardPosition, offset); + } + } else { + for (int j = 0; j < label.forwardReferenceCount; j++) { + int forwardPosition = label.forwardReferences[j]; + int offset = position - forwardPosition + 1; + if (offset > 0x7FFF && !this.codeStream.wideMode) { + throw new AbortMethod(CodeStream.RESTART_IN_WIDE_MODE); + } + if (this.codeStream.wideMode) { + if (this.isWide) { + codeStream.writeSignedWord(forwardPosition, offset); + } else { + codeStream.writeSignedShort(forwardPosition, (short) offset); + } + } else { + codeStream.writeSignedShort(forwardPosition, (short) offset); + } + } + } + } + } + } + } +} +/** + * Print out the receiver + */ +public String toString() { + StringBuffer buffer = new StringBuffer("(position="); //$NON-NLS-1$ + buffer.append(position); + buffer.append(", forwards = ["); //$NON-NLS-1$ + for (int i = 0; i < forwardReferenceCount - 1; i++) + buffer.append(forwardReferences[i] + ", "); //$NON-NLS-1$ + if (forwardReferenceCount >= 1) + buffer.append(forwardReferences[forwardReferenceCount-1]); + buffer.append("] )"); //$NON-NLS-1$ + return buffer.toString(); +} + +public void resetStateForCodeGeneration() { + this.position = POS_NOT_SET; + this.forwardReferenceCount = 0; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/LongCache.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/LongCache.java new file mode 100644 index 0000000..770cbc4 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/LongCache.java @@ -0,0 +1,155 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.codegen; + +public class LongCache { + public long keyTable[]; + public int valueTable[]; + int elementSize; + int threshold; +/** + * Constructs a new, empty hashtable. A default capacity and + * load factor is used. Note that the hashtable will automatically + * grow when it gets full. + */ +public LongCache() { + this(13); +} +/** + * Constructs a new, empty hashtable with the specified initial + * capacity. + * @param initialCapacity int + * the initial number of buckets + */ +public LongCache(int initialCapacity) { + elementSize = 0; + threshold = (int) (initialCapacity * 0.66); + keyTable = new long[initialCapacity]; + valueTable = new int[initialCapacity]; +} +/** + * Clears the hash table so that it has no more elements in it. + */ +public void clear() { + for (int i = keyTable.length; --i >= 0;) { + keyTable[i] = 0; + valueTable[i] = 0; + } + elementSize = 0; +} +/** Returns true if the collection contains an element for the key. + * + * @param key long the key that we are looking for + * @return boolean + */ +public boolean containsKey(long key) { + int index = hash(key); + while ((keyTable[index] != 0) || ((keyTable[index] == 0) &&(valueTable[index] != 0))) { + if (keyTable[index] == key) + return true; + index = (index + 1) % keyTable.length; + } + return false; +} +/** Gets the object associated with the specified key in the + * hashtable. + * @param key long the specified key + * @return int the element for the key or -1 if the key is not + * defined in the hash table. + */ +public int get(long key) { + int index = hash(key); + while ((keyTable[index] != 0) || ((keyTable[index] == 0) &&(valueTable[index] != 0))) { + if (keyTable[index] == key) + return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return -1; +} +/** + * Return a hashcode for the value of the key parameter. + * @param key long + * @return int the hash code corresponding to the key value + */ +public int hash(long key) { + return ((int) key & 0x7FFFFFFF) % keyTable.length; +} +/** + * Puts the specified element into the hashtable, using the specified + * key. The element may be retrieved by doing a get() with the same key. + * + * @param key long the specified key in the hashtable + * @param value int the specified element + * @return int value + */ +public int put(long key, int value) { + int index = hash(key); + while ((keyTable[index] != 0) || ((keyTable[index] == 0) && (valueTable[index] != 0))) { + if (keyTable[index] == key) + return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) { + rehash(); + } + return value; +} +/** + * Rehashes the content of the table into a bigger table. + * This method is called automatically when the hashtable's + * size exceeds the threshold. + */ +private void rehash() { + LongCache newHashtable = new LongCache(keyTable.length * 2); + for (int i = keyTable.length; --i >= 0;) { + long key = keyTable[i]; + int value = valueTable[i]; + if ((key != 0) || ((key == 0) && (value != 0))) { + newHashtable.put(key, value); + } + } + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; +} +/** + * Returns the number of elements contained in the hashtable. + * + * @return int The size of the table + */ +public int size() { + return elementSize; +} +/** + * Converts to a rather lengthy String. + * + * @return String the ascii representation of the receiver + */ +public String toString() { + int max = size(); + StringBuffer buf = new StringBuffer(); + buf.append("{"); //$NON-NLS-1$ + for (int i = 0; i < max; ++i) { + if ((keyTable[i] != 0) || ((keyTable[i] == 0) && (valueTable[i] != 0))) { + buf.append(keyTable[i]).append("->").append(valueTable[i]); //$NON-NLS-1$ + } + if (i < max) { + buf.append(", "); //$NON-NLS-1$ + } + } + buf.append("}"); //$NON-NLS-1$ + return buf.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/MethodNameAndTypeCache.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/MethodNameAndTypeCache.java new file mode 100644 index 0000000..ff79e4c --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/MethodNameAndTypeCache.java @@ -0,0 +1,162 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.codegen; + +import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class MethodNameAndTypeCache { + public MethodBinding keyTable[]; + public int valueTable[]; + int elementSize; + int threshold; +/** + * Constructs a new, empty hashtable. A default capacity is used. + * Note that the hashtable will automatically grow when it gets full. + */ +public MethodNameAndTypeCache() { + this(13); +} +/** + * Constructs a new, empty hashtable with the specified initial + * capacity. + * @param initialCapacity int + * the initial number of buckets + */ +public MethodNameAndTypeCache(int initialCapacity) { + this.elementSize = 0; + this.threshold = (int) (initialCapacity * 0.66f); + this.keyTable = new MethodBinding[initialCapacity]; + this.valueTable = new int[initialCapacity]; +} +/** + * Clears the hash table so that it has no more elements in it. + */ +public void clear() { + for (int i = keyTable.length; --i >= 0;) { + keyTable[i] = null; + valueTable[i] = 0; + } + elementSize = 0; +} +/** Returns true if the collection contains an element for the key. + * + * @param char[] key the key that we are looking for + * @return boolean + */ +public boolean containsKey(MethodBinding key) { + int index = hashCode(key); + while (keyTable[index] != null) { + if (equalsForNameAndType(keyTable[index], key)) + return true; + index = (index + 1) % keyTable.length; + } + return false; +} +/** + * Returns true if the two methodBinding are consider to be equal for the name and type + * purpose + */ +public boolean equalsForNameAndType(MethodBinding method1, MethodBinding method2) { + return CharOperation.equals(method1.selector, method2.selector) && CharOperation.equals(method1.signature(), method2.signature()); +} +/** Gets the object associated with the specified key in the + * hashtable. + * @param key char[] the specified key + * @return int the element for the key or -1 if the key is not + * defined in the hash table. + */ +public int get(MethodBinding key) { + int index = hashCode(key); + while (keyTable[index] != null) { + if (equalsForNameAndType(keyTable[index], key)) + return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return -1; +} +/** + * Return the hashcode for the key parameter + * + * @param key org.eclipse.jdt.internal.compiler.lookup.MethodBinding + * @return int + */ +public int hashCode(MethodBinding key) { + return CharOperation.hashCode(key.selector) % keyTable.length; +} +/** + * Puts the specified element into the hashtable, using the specified + * key. The element may be retrieved by doing a get() with the same key. + * The key and the element cannot be null. + * + * @param key Object the specified key in the hashtable + * @param value int the specified element + * @return int the old value of the key, or -1 if it did not have one. + */ +public int put(MethodBinding key, int value) { + int index = hashCode(key); + while (keyTable[index] != null) { + if (equalsForNameAndType(keyTable[index], key)) + return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) + rehash(); + return value; +} +/** + * Rehashes the content of the table into a bigger table. + * This method is called automatically when the hashtable's + * size exceeds the threshold. + */ +private void rehash() { + MethodNameAndTypeCache newHashtable = new MethodNameAndTypeCache(keyTable.length * 2); + for (int i = keyTable.length; --i >= 0;) + if (keyTable[i] != null) + newHashtable.put(keyTable[i], valueTable[i]); + + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; +} +/** + * Returns the number of elements contained in the hashtable. + * + * @return int The size of the table + */ +public int size() { + return elementSize; +} +/** + * Converts to a rather lengthy String. + * + * @return String the ascii representation of the receiver + */ +public String toString() { + int max = size(); + StringBuffer buf = new StringBuffer(); + buf.append("{"); //$NON-NLS-1$ + for (int i = 0; i < max; ++i) { + if (keyTable[i] != null) { + buf.append(keyTable[i]).append("->").append(valueTable[i]); //$NON-NLS-1$ + } + if (i < max) { + buf.append(", "); //$NON-NLS-1$ + } + } + buf.append("}"); //$NON-NLS-1$ + return buf.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/ObjectCache.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/ObjectCache.java new file mode 100644 index 0000000..a2ed4a5 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/ObjectCache.java @@ -0,0 +1,152 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.codegen; + +public class ObjectCache { + public Object keyTable[]; + public int valueTable[]; + int elementSize; + int threshold; +/** + * Constructs a new, empty hashtable. A default capacity is used. + * Note that the hashtable will automatically grow when it gets full. + */ +public ObjectCache() { + this(13); +} +/** + * Constructs a new, empty hashtable with the specified initial + * capacity. + * @param initialCapacity int + * the initial number of buckets + */ +public ObjectCache(int initialCapacity) { + this.elementSize = 0; + this.threshold = (int) (initialCapacity * 0.66f); + this.keyTable = new Object[initialCapacity]; + this.valueTable = new int[initialCapacity]; +} +/** + * Clears the hash table so that it has no more elements in it. + */ +public void clear() { + for (int i = keyTable.length; --i >= 0;) { + keyTable[i] = null; + valueTable[i] = 0; + } + elementSize = 0; +} +/** Returns true if the collection contains an element for the key. + * + * @param char[] key the key that we are looking for + * @return boolean + */ +public boolean containsKey(Object key) { + int index = hashCode(key); + while (keyTable[index] != null) { + if (keyTable[index] == key) + return true; + index = (index + 1) % keyTable.length; + } + return false; +} +/** Gets the object associated with the specified key in the + * hashtable. + * @param key char[] the specified key + * @return int the element for the key or -1 if the key is not + * defined in the hash table. + */ +public int get(Object key) { + int index = hashCode(key); + while (keyTable[index] != null) { + if (keyTable[index] == key) + return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return -1; +} +/** + * Return the hashcode for the key parameter + * + * @param key org.eclipse.jdt.internal.compiler.lookup.MethodBinding + * @return int + */ +public int hashCode(Object key) { + return (key.hashCode() & 0x7FFFFFFF) % keyTable.length; +} +/** + * Puts the specified element into the hashtable, using the specified + * key. The element may be retrieved by doing a get() with the same key. + * The key and the element cannot be null. + * + * @param key Object the specified key in the hashtable + * @param value int the specified element + * @return int the old value of the key, or -1 if it did not have one. + */ +public int put(Object key, int value) { + int index = hashCode(key); + while (keyTable[index] != null) { + if (keyTable[index] == key) + return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) + rehash(); + return value; +} +/** + * Rehashes the content of the table into a bigger table. + * This method is called automatically when the hashtable's + * size exceeds the threshold. + */ +private void rehash() { + ObjectCache newHashtable = new ObjectCache(keyTable.length * 2); + for (int i = keyTable.length; --i >= 0;) + if (keyTable[i] != null) + newHashtable.put(keyTable[i], valueTable[i]); + + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; +} +/** + * Returns the number of elements contained in the hashtable. + * + * @return int The size of the table + */ +public int size() { + return elementSize; +} +/** + * Converts to a rather lengthy String. + * + * @return String the ascii representation of the receiver + */ +public String toString() { + int max = size(); + StringBuffer buf = new StringBuffer(); + buf.append("{"); //$NON-NLS-1$ + for (int i = 0; i < max; ++i) { + if (keyTable[i] != null) { + buf.append(keyTable[i]).append("->").append(valueTable[i]); //$NON-NLS-1$ + } + if (i < max) { + buf.append(", "); //$NON-NLS-1$ + } + } + buf.append("}"); //$NON-NLS-1$ + return buf.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/Opcodes.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/Opcodes.java new file mode 100644 index 0000000..c88efba --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/Opcodes.java @@ -0,0 +1,216 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.codegen; + +public interface Opcodes { + + public static final byte OPC_nop = 0; + public static final byte OPC_aconst_null = 1; + public static final byte OPC_iconst_m1 = 2; + public static final byte OPC_iconst_0 = 3; + public static final byte OPC_iconst_1 = 4; + public static final byte OPC_iconst_2 = 5; + public static final byte OPC_iconst_3 = 6; + public static final byte OPC_iconst_4 = 7; + public static final byte OPC_iconst_5 = 8; + public static final byte OPC_lconst_0 = 9; + public static final byte OPC_lconst_1 = 10; + public static final byte OPC_fconst_0 = 11; + public static final byte OPC_fconst_1 = 12; + public static final byte OPC_fconst_2 = 13; + public static final byte OPC_dconst_0 = 14; + public static final byte OPC_dconst_1 = 15; + public static final byte OPC_bipush = 16; + public static final byte OPC_sipush = 17; + public static final byte OPC_ldc = 18; + public static final byte OPC_ldc_w = 19; + public static final byte OPC_ldc2_w = 20; + public static final byte OPC_iload = 21; + public static final byte OPC_lload = 22; + public static final byte OPC_fload = 23; + public static final byte OPC_dload = 24; + public static final byte OPC_aload = 25; + public static final byte OPC_iload_0 = 26; + public static final byte OPC_iload_1 = 27; + public static final byte OPC_iload_2 = 28; + public static final byte OPC_iload_3 = 29; + public static final byte OPC_lload_0 = 30; + public static final byte OPC_lload_1 = 31; + public static final byte OPC_lload_2 = 32; + public static final byte OPC_lload_3 = 33; + public static final byte OPC_fload_0 = 34; + public static final byte OPC_fload_1 = 35; + public static final byte OPC_fload_2 = 36; + public static final byte OPC_fload_3 = 37; + public static final byte OPC_dload_0 = 38; + public static final byte OPC_dload_1 = 39; + public static final byte OPC_dload_2 = 40; + public static final byte OPC_dload_3 = 41; + public static final byte OPC_aload_0 = 42; + public static final byte OPC_aload_1 = 43; + public static final byte OPC_aload_2 = 44; + public static final byte OPC_aload_3 = 45; + public static final byte OPC_iaload = 46; + public static final byte OPC_laload = 47; + public static final byte OPC_faload = 48; + public static final byte OPC_daload = 49; + public static final byte OPC_aaload = 50; + public static final byte OPC_baload = 51; + public static final byte OPC_caload = 52; + public static final byte OPC_saload = 53; + public static final byte OPC_istore = 54; + public static final byte OPC_lstore = 55; + public static final byte OPC_fstore = 56; + public static final byte OPC_dstore = 57; + public static final byte OPC_astore = 58; + public static final byte OPC_istore_0 = 59; + public static final byte OPC_istore_1 = 60; + public static final byte OPC_istore_2 = 61; + public static final byte OPC_istore_3 = 62; + public static final byte OPC_lstore_0 = 63; + public static final byte OPC_lstore_1 = 64; + public static final byte OPC_lstore_2 = 65; + public static final byte OPC_lstore_3 = 66; + public static final byte OPC_fstore_0 = 67; + public static final byte OPC_fstore_1 = 68; + public static final byte OPC_fstore_2 = 69; + public static final byte OPC_fstore_3 = 70; + public static final byte OPC_dstore_0 = 71; + public static final byte OPC_dstore_1 = 72; + public static final byte OPC_dstore_2 = 73; + public static final byte OPC_dstore_3 = 74; + public static final byte OPC_astore_0 = 75; + public static final byte OPC_astore_1 = 76; + public static final byte OPC_astore_2 = 77; + public static final byte OPC_astore_3 = 78; + public static final byte OPC_iastore = 79; + public static final byte OPC_lastore = 80; + public static final byte OPC_fastore = 81; + public static final byte OPC_dastore = 82; + public static final byte OPC_aastore = 83; + public static final byte OPC_bastore = 84; + public static final byte OPC_castore = 85; + public static final byte OPC_sastore = 86; + public static final byte OPC_pop = 87; + public static final byte OPC_pop2 = 88; + public static final byte OPC_dup = 89; + public static final byte OPC_dup_x1 = 90; + public static final byte OPC_dup_x2 = 91; + public static final byte OPC_dup2 = 92; + public static final byte OPC_dup2_x1 = 93; + public static final byte OPC_dup2_x2 = 94; + public static final byte OPC_swap = 95; + public static final byte OPC_iadd = 96; + public static final byte OPC_ladd = 97; + public static final byte OPC_fadd = 98; + public static final byte OPC_dadd = 99; + public static final byte OPC_isub = 100; + public static final byte OPC_lsub = 101; + public static final byte OPC_fsub = 102; + public static final byte OPC_dsub = 103; + public static final byte OPC_imul = 104; + public static final byte OPC_lmul = 105; + public static final byte OPC_fmul = 106; + public static final byte OPC_dmul = 107; + public static final byte OPC_idiv = 108; + public static final byte OPC_ldiv = 109; + public static final byte OPC_fdiv = 110; + public static final byte OPC_ddiv = 111; + public static final byte OPC_irem = 112; + public static final byte OPC_lrem = 113; + public static final byte OPC_frem = 114; + public static final byte OPC_drem = 115; + public static final byte OPC_ineg = 116; + public static final byte OPC_lneg = 117; + public static final byte OPC_fneg = 118; + public static final byte OPC_dneg = 119; + public static final byte OPC_ishl = 120; + public static final byte OPC_lshl = 121; + public static final byte OPC_ishr = 122; + public static final byte OPC_lshr = 123; + public static final byte OPC_iushr = 124; + public static final byte OPC_lushr = 125; + public static final byte OPC_iand = 126; + public static final byte OPC_land = 127; + public static final byte OPC_ior = (byte) 128; + public static final byte OPC_lor = (byte) 129; + public static final byte OPC_ixor = (byte) 130; + public static final byte OPC_lxor = (byte) 131; + public static final byte OPC_iinc = (byte) 132; + public static final byte OPC_i2l = (byte) 133; + public static final byte OPC_i2f = (byte) 134; + public static final byte OPC_i2d = (byte) 135; + public static final byte OPC_l2i = (byte) 136; + public static final byte OPC_l2f = (byte) 137; + public static final byte OPC_l2d = (byte) 138; + public static final byte OPC_f2i = (byte) 139; + public static final byte OPC_f2l = (byte) 140; + public static final byte OPC_f2d = (byte) 141; + public static final byte OPC_d2i = (byte) 142; + public static final byte OPC_d2l = (byte) 143; + public static final byte OPC_d2f = (byte) 144; + public static final byte OPC_i2b = (byte) 145; + public static final byte OPC_i2c = (byte) 146; + public static final byte OPC_i2s = (byte) 147; + public static final byte OPC_lcmp = (byte) 148; + public static final byte OPC_fcmpl = (byte) 149; + public static final byte OPC_fcmpg = (byte) 150; + public static final byte OPC_dcmpl = (byte) 151; + public static final byte OPC_dcmpg = (byte) 152; + public static final byte OPC_ifeq = (byte) 153; + public static final byte OPC_ifne = (byte) 154; + public static final byte OPC_iflt = (byte) 155; + public static final byte OPC_ifge = (byte) 156; + public static final byte OPC_ifgt = (byte) 157; + public static final byte OPC_ifle = (byte) 158; + public static final byte OPC_if_icmpeq = (byte) 159; + public static final byte OPC_if_icmpne = (byte) 160; + public static final byte OPC_if_icmplt = (byte) 161; + public static final byte OPC_if_icmpge = (byte) 162; + public static final byte OPC_if_icmpgt = (byte) 163; + public static final byte OPC_if_icmple = (byte) 164; + public static final byte OPC_if_acmpeq = (byte) 165; + public static final byte OPC_if_acmpne = (byte) 166; + public static final byte OPC_goto = (byte) 167; + public static final byte OPC_jsr = (byte) 168; + public static final byte OPC_ret = (byte) 169; + public static final byte OPC_tableswitch = (byte) 170; + public static final byte OPC_lookupswitch = (byte) 171; + public static final byte OPC_ireturn = (byte) 172; + public static final byte OPC_lreturn = (byte) 173; + public static final byte OPC_freturn = (byte) 174; + public static final byte OPC_dreturn = (byte) 175; + public static final byte OPC_areturn = (byte) 176; + public static final byte OPC_return = (byte) 177; + public static final byte OPC_getstatic = (byte) 178; + public static final byte OPC_putstatic = (byte) 179; + public static final byte OPC_getfield = (byte) 180; + public static final byte OPC_putfield = (byte) 181; + public static final byte OPC_invokevirtual = (byte) 182; + public static final byte OPC_invokespecial = (byte) 183; + public static final byte OPC_invokestatic = (byte) 184; + public static final byte OPC_invokeinterface = (byte) 185; + public static final byte OPC_new = (byte) 187; + public static final byte OPC_newarray = (byte) 188; + public static final byte OPC_anewarray = (byte) 189; + public static final byte OPC_arraylength = (byte) 190; + public static final byte OPC_athrow = (byte) 191; + public static final byte OPC_checkcast = (byte) 192; + public static final byte OPC_instanceof = (byte) 193; + public static final byte OPC_monitorenter = (byte) 194; + public static final byte OPC_monitorexit = (byte) 195; + public static final byte OPC_wide = (byte) 196; + public static final byte OPC_multianewarray = (byte) 197; + public static final byte OPC_ifnull = (byte) 198; + public static final byte OPC_ifnonnull = (byte) 199; + public static final byte OPC_goto_w = (byte) 200; + public static final byte OPC_jsr_w = (byte) 201; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/QualifiedNamesConstants.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/QualifiedNamesConstants.java new file mode 100644 index 0000000..64613b4 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/QualifiedNamesConstants.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.codegen; + +public interface QualifiedNamesConstants { + char[] JavaLangObjectConstantPoolName = "java/lang/Object".toCharArray(); //$NON-NLS-1$ + char[] JavaLangStringConstantPoolName = "java/lang/String".toCharArray(); //$NON-NLS-1$ + char[] JavaLangStringBufferConstantPoolName = "java/lang/StringBuffer".toCharArray(); //$NON-NLS-1$ + char[] JavaLangClassConstantPoolName = "java/lang/Class".toCharArray(); //$NON-NLS-1$ + char[] JavaLangThrowableConstantPoolName = "java/lang/Throwable".toCharArray(); //$NON-NLS-1$ + char[] JavaLangClassNotFoundExceptionConstantPoolName = "java/lang/ClassNotFoundException".toCharArray(); //$NON-NLS-1$ + char[] JavaLangNoClassDefFoundErrorConstantPoolName = "java/lang/NoClassDefFoundError".toCharArray(); //$NON-NLS-1$ + char[] JavaLangIntegerConstantPoolName = "java/lang/Integer".toCharArray(); //$NON-NLS-1$ + char[] JavaLangFloatConstantPoolName = "java/lang/Float".toCharArray(); //$NON-NLS-1$ + char[] JavaLangDoubleConstantPoolName = "java/lang/Double".toCharArray(); //$NON-NLS-1$ + char[] JavaLangLongConstantPoolName = "java/lang/Long".toCharArray(); //$NON-NLS-1$ + char[] JavaLangShortConstantPoolName = "java/lang/Short".toCharArray(); //$NON-NLS-1$ + char[] JavaLangByteConstantPoolName = "java/lang/Byte".toCharArray(); //$NON-NLS-1$ + char[] JavaLangCharacterConstantPoolName = "java/lang/Character".toCharArray(); //$NON-NLS-1$ + char[] JavaLangVoidConstantPoolName = "java/lang/Void".toCharArray(); //$NON-NLS-1$ + char[] JavaLangBooleanConstantPoolName = "java/lang/Boolean".toCharArray(); //$NON-NLS-1$ + char[] JavaLangSystemConstantPoolName = "java/lang/System".toCharArray(); //$NON-NLS-1$ + char[] JavaLangErrorConstantPoolName = "java/lang/Error".toCharArray(); //$NON-NLS-1$ + char[] JavaLangExceptionConstantPoolName = "java/lang/Exception".toCharArray(); //$NON-NLS-1$ + char[] JavaLangReflectConstructor = "java/lang/reflect/Constructor".toCharArray(); //$NON-NLS-1$ + char[] Append = new char[] {'a', 'p', 'p', 'e', 'n', 'd'}; + char[] ToString = new char[] {'t', 'o', 'S', 't', 'r', 'i', 'n', 'g'}; + char[] Init = new char[] {'<', 'i', 'n', 'i', 't', '>'}; + char[] Clinit = new char[] {'<', 'c', 'l', 'i', 'n', 'i', 't', '>'}; + char[] ValueOf = new char[] {'v', 'a', 'l', 'u', 'e', 'O', 'f'}; + char[] ForName = new char[] {'f', 'o', 'r', 'N', 'a', 'm', 'e'}; + char[] GetMessage = new char[] {'g', 'e', 't', 'M', 'e', 's', 's', 'a', 'g', 'e'}; + char[] NewInstance = "newInstance".toCharArray(); //$NON-NLS-1$ + char[] GetConstructor = "getConstructor".toCharArray(); //$NON-NLS-1$ + char[] Exit = new char[] {'e', 'x', 'i', 't'}; + char[] Intern = "intern".toCharArray(); //$NON-NLS-1$ + char[] Out = new char[] {'o', 'u', 't'}; + char[] TYPE = new char[] {'T', 'Y', 'P', 'E'}; + char[] This = new char[] {'t', 'h', 'i', 's'}; + char[] JavaLangClassSignature = new char[] {'L', 'j', 'a', 'v', 'a', '/', 'l', 'a', 'n', 'g', '/', 'C', 'l', 'a', 's', 's', ';'}; + char[] ForNameSignature = "(Ljava/lang/String;)Ljava/lang/Class;".toCharArray(); //$NON-NLS-1$ + char[] GetMessageSignature = "()Ljava/lang/String;".toCharArray(); //$NON-NLS-1$ + char[] GetConstructorSignature = "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;".toCharArray(); //$NON-NLS-1$ + char[] StringConstructorSignature = "(Ljava/lang/String;)V".toCharArray(); //$NON-NLS-1$ + char[] NewInstanceSignature = "([Ljava/lang/Object;)Ljava/lang/Object;".toCharArray(); //$NON-NLS-1$ + char[] DefaultConstructorSignature = {'(', ')', 'V'}; + char[] ClinitSignature = DefaultConstructorSignature; + char[] ToStringSignature = GetMessageSignature; + char[] InternSignature = GetMessageSignature; + char[] AppendIntSignature = "(I)Ljava/lang/StringBuffer;".toCharArray(); //$NON-NLS-1$ + char[] AppendLongSignature = "(J)Ljava/lang/StringBuffer;".toCharArray(); //$NON-NLS-1$ + char[] AppendFloatSignature = "(F)Ljava/lang/StringBuffer;".toCharArray(); //$NON-NLS-1$ + char[] AppendDoubleSignature = "(D)Ljava/lang/StringBuffer;".toCharArray(); //$NON-NLS-1$ + char[] AppendCharSignature = "(C)Ljava/lang/StringBuffer;".toCharArray(); //$NON-NLS-1$ + char[] AppendBooleanSignature = "(Z)Ljava/lang/StringBuffer;".toCharArray(); //$NON-NLS-1$ + char[] AppendObjectSignature = "(Ljava/lang/Object;)Ljava/lang/StringBuffer;".toCharArray(); //$NON-NLS-1$ + char[] AppendStringSignature = "(Ljava/lang/String;)Ljava/lang/StringBuffer;".toCharArray(); //$NON-NLS-1$ + char[] ValueOfObjectSignature = "(Ljava/lang/Object;)Ljava/lang/String;".toCharArray(); //$NON-NLS-1$ + char[] ValueOfIntSignature = "(I)Ljava/lang/String;".toCharArray(); //$NON-NLS-1$ + char[] ValueOfLongSignature = "(J)Ljava/lang/String;".toCharArray(); //$NON-NLS-1$ + char[] ValueOfCharSignature = "(C)Ljava/lang/String;".toCharArray(); //$NON-NLS-1$ + char[] ValueOfBooleanSignature = "(Z)Ljava/lang/String;".toCharArray(); //$NON-NLS-1$ + char[] ValueOfDoubleSignature = "(D)Ljava/lang/String;".toCharArray(); //$NON-NLS-1$ + char[] ValueOfFloatSignature = "(F)Ljava/lang/String;".toCharArray(); //$NON-NLS-1$ + char[] JavaIoPrintStreamSignature = "Ljava/io/PrintStream;".toCharArray(); //$NON-NLS-1$ + char[] ExitIntSignature = new char[] {'(', 'I', ')', 'V'}; + char[] ArrayJavaLangObjectConstantPoolName = "[Ljava/lang/Object;".toCharArray(); //$NON-NLS-1$ + char[] ArrayJavaLangClassConstantPoolName = "[Ljava/lang/Class;".toCharArray(); //$NON-NLS-1$ + char[] JavaLangAssertionErrorConstantPoolName = "java/lang/AssertionError".toCharArray(); //$NON-NLS-1$ + char[] AssertionErrorIntConstrSignature = "(I)V".toCharArray(); //$NON-NLS-1$ + char[] AssertionErrorLongConstrSignature = "(J)V".toCharArray(); //$NON-NLS-1$ + char[] AssertionErrorFloatConstrSignature = "(F)V".toCharArray(); //$NON-NLS-1$ + char[] AssertionErrorDoubleConstrSignature = "(D)V".toCharArray(); //$NON-NLS-1$ + char[] AssertionErrorCharConstrSignature = "(C)V".toCharArray(); //$NON-NLS-1$ + char[] AssertionErrorBooleanConstrSignature = "(Z)V".toCharArray(); //$NON-NLS-1$ + char[] AssertionErrorObjectConstrSignature = "(Ljava/lang/Object;)V".toCharArray(); //$NON-NLS-1$ + char[] DesiredAssertionStatus = "desiredAssertionStatus".toCharArray(); //$NON-NLS-1$ + char[] DesiredAssertionStatusSignature = "()Z".toCharArray(); //$NON-NLS-1$ + char[] ShortConstrSignature = "(S)V".toCharArray(); //$NON-NLS-1$ + char[] ByteConstrSignature = "(B)V".toCharArray(); //$NON-NLS-1$ + char[] GetClass = "getClass".toCharArray(); //$NON-NLS-1$ + char[] GetClassSignature = "()Ljava/lang/Class;".toCharArray(); //$NON-NLS-1$ + +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/ResetStateForCodeGenerationVisitor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/ResetStateForCodeGenerationVisitor.java new file mode 100644 index 0000000..a6b1d59 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/codegen/ResetStateForCodeGenerationVisitor.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.codegen; + +import net.sourceforge.phpdt.internal.compiler.AbstractSyntaxTreeVisitorAdapter; +import net.sourceforge.phpdt.internal.compiler.ast.BranchStatement; +import net.sourceforge.phpdt.internal.compiler.ast.DoStatement; +import net.sourceforge.phpdt.internal.compiler.ast.ForStatement; +import net.sourceforge.phpdt.internal.compiler.ast.LabeledStatement; +import net.sourceforge.phpdt.internal.compiler.ast.SwitchStatement; +import net.sourceforge.phpdt.internal.compiler.ast.WhileStatement; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; + +public class ResetStateForCodeGenerationVisitor + extends AbstractSyntaxTreeVisitorAdapter { + + public boolean visit(SwitchStatement statement, BlockScope scope) { + statement.resetStateForCodeGeneration(); + return true; + } + + public boolean visit(ForStatement forStatement, BlockScope scope) { + forStatement.resetStateForCodeGeneration(); + return true; + } + + public boolean visit(WhileStatement whileStatement, BlockScope scope) { + whileStatement.resetStateForCodeGeneration(); + return true; + } + + public boolean visit(LabeledStatement labeledStatement, BlockScope scope) { + labeledStatement.resetStateForCodeGeneration(); + return true; + } + + public boolean visit(DoStatement doStatement, BlockScope scope) { + doStatement.resetStateForCodeGeneration(); + return true; + } + + public boolean visit(BranchStatement branchStatement, BlockScope scope) { + branchStatement.resetStateForCodeGeneration(); + return true; + } + +} + diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IBinaryField.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IBinaryField.java new file mode 100644 index 0000000..3297891 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IBinaryField.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.env; + +import net.sourceforge.phpdt.internal.compiler.impl.Constant; + +public interface IBinaryField extends IGenericField { +/** + * + * @return org.eclipse.jdt.internal.compiler.Constant + */ +Constant getConstant(); +/** + * Answer the resolved name of the receiver's type in the + * class file format as specified in section 4.3.2 of the Java 2 VM spec. + * + * For example: + * - java.lang.String is Ljava/lang/String; + * - an int is I + * - a 2 dimensional array of strings is [[Ljava/lang/String; + * - an array of floats is [F + */ + +char[] getTypeName(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IBinaryMethod.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IBinaryMethod.java new file mode 100644 index 0000000..59511d0 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IBinaryMethod.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.env; + +// clinit methods (synthetics too?) can be returned from IBinaryType>>getMethods() +// BUT do not have to be... the compiler will ignore them when building the binding. +// The synthetic argument of a member type's constructor (ie. the first arg of a non-static +// member type) is also ignored by the compiler, BUT in this case it must be included +// in the constructor's signature. + +public interface IBinaryMethod extends IGenericMethod { + +/** + * Answer the resolved names of the exception types in the + * class file format as specified in section 4.2 of the Java 2 VM spec + * or null if the array is empty. + * + * For example, java.lang.String is java/lang/String. + */ +char[][] getExceptionTypeNames(); + +/** + * Answer the receiver's method descriptor which describes the parameter & + * return types as specified in section 4.3.3 of the Java 2 VM spec. + * + * For example: + * - int foo(String) is (Ljava/lang/String;)I + * - Object[] foo(int) is (I)[Ljava/lang/Object; + */ +char[] getMethodDescriptor(); + +/** + * Answer whether the receiver represents a class initializer method. + */ +boolean isClinit(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IBinaryNestedType.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IBinaryNestedType.java new file mode 100644 index 0000000..0b2e6b5 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IBinaryNestedType.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.env; + +public interface IBinaryNestedType { +/** + * Answer the resolved name of the enclosing type in the + * class file format as specified in section 4.2 of the Java 2 VM spec. + * + * For example, java.lang.String is java/lang/String. + */ + +char[] getEnclosingTypeName(); +/** + * Answer an int whose bits are set according the access constants + * defined by the VM spec. + */ + +// We have added AccDeprecated & AccSynthetic. + +int getModifiers(); +/** + * Answer the resolved name of the member type in the + * class file format as specified in section 4.2 of the Java 2 VM spec. + * + * For example, p1.p2.A.M is p1/p2/A$M. + */ + +char[] getName(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IBinaryType.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IBinaryType.java new file mode 100644 index 0000000..18ec241 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IBinaryType.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.env; + +public interface IBinaryType extends IGenericType { + + char[][] NoInterface = new char[0][]; + IBinaryNestedType[] NoNestedType = new IBinaryNestedType[0]; + IBinaryField[] NoField = new IBinaryField[0]; + IBinaryMethod[] NoMethod = new IBinaryMethod[0]; +/** + * Answer the resolved name of the enclosing type in the + * class file format as specified in section 4.2 of the Java 2 VM spec + * or null if the receiver is a top level type. + * + * For example, java.lang.String is java/lang/String. + */ + +char[] getEnclosingTypeName(); +/** + * Answer the receiver's fields or null if the array is empty. + */ + +IBinaryField[] getFields(); +/** + * Answer the resolved names of the receiver's interfaces in the + * class file format as specified in section 4.2 of the Java 2 VM spec + * or null if the array is empty. + * + * For example, java.lang.String is java/lang/String. + */ + +char[][] getInterfaceNames(); +/** + * Answer the receiver's nested types or null if the array is empty. + * + * This nested type info is extracted from the inner class attributes. + * Ask the name environment to find a member type using its compound name. + */ + +// NOTE: The compiler examines the nested type info & ignores the local types +// so the local types do not have to be included. + +IBinaryNestedType[] getMemberTypes(); +/** + * Answer the receiver's methods or null if the array is empty. + */ + +IBinaryMethod[] getMethods(); +/** + * Answer the resolved name of the type in the + * class file format as specified in section 4.2 of the Java 2 VM spec. + * + * For example, java.lang.String is java/lang/String. + */ + +char[] getName(); +/** + * Answer the resolved name of the receiver's superclass in the + * class file format as specified in section 4.2 of the Java 2 VM spec + * or null if it does not have one. + * + * For example, java.lang.String is java/lang/String. + */ + +char[] getSuperclassName(); + +/** + * Answer true if the receiver is an anonymous class. + * false otherwise + */ +boolean isAnonymous(); + +/** + * Answer true if the receiver is a local class. + * false otherwise + */ +boolean isLocal(); + +/** + * Answer true if the receiver is a member class. + * false otherwise + */ +boolean isMember(); + +/** + * Answer the source file attribute, or null if none. + * + * For example, "String.java" + */ + +char[] sourceFileName(); + +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/ICompilationUnit.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/ICompilationUnit.java new file mode 100644 index 0000000..da9d184 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/ICompilationUnit.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.env; + +/** + * This interface denotes a compilation unit, providing its name and content. + */ +public interface ICompilationUnit extends IDependent { +/** + * Answer the contents of the compilation unit. + * + * In normal use, the contents are requested twice. + * Once during the initial lite parsing step, then again for the + * more detailed parsing step. + */ +char[] getContents(); +/** + * Answer the name of the top level public type. + * For example, {Hashtable}. + */ +char[] getMainTypeName(); +/** + * Answer the name of the package according to the directory structure + * or null if package consistency checks should be ignored. + * For example, {java, lang}. + */ +char[][] getPackageName(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IConstants.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IConstants.java new file mode 100644 index 0000000..0fbd8bd --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IConstants.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.env; + +/** + * This interface defines constants for use by the builder / compiler interface. + */ +public interface IConstants { + + /* + * Modifiers + */ + int AccPublic = 0x0001; + int AccPrivate = 0x0002; + int AccProtected = 0x0004; + int AccStatic = 0x0008; + int AccFinal = 0x0010; + int AccSynchronized = 0x0020; + int AccVolatile = 0x0040; + int AccTransient = 0x0080; + int AccNative = 0x0100; + int AccInterface = 0x0200; + int AccAbstract = 0x0400; + int AccStrictfp = 0x0800; + + /* + * Other VM flags. + */ + int AccSuper = 0x0020; + + /** + * Extra flags for types and members. + */ + int AccSynthetic = 0x20000; + int AccDeprecated = 0x100000; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IDependent.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IDependent.java new file mode 100644 index 0000000..fb839eb --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IDependent.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.env; + +/** + * This represents the target (i.e. the file) of a type dependency. + * + * All implementors of this interface are containers for types or types + * themselves which must be able to identify their source file name + * when file dependencies are collected. + */ +public interface IDependent { +/** + * Answer the file name which defines the type. + * + * The path part (optional) must be separated from the actual + * file proper name by a java.io.File.separator. + * + * The proper file name includes the suffix extension (e.g. ".java") + * + * e.g. "c:/com/ibm/compiler/java/api/Compiler.java" + */ + +char[] getFileName(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IGenericField.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IGenericField.java new file mode 100644 index 0000000..c87e486 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IGenericField.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.env; + +public interface IGenericField { +/** + * Answer an int whose bits are set according the access constants + * defined by the VM spec. + */ + +// We have added AccDeprecated & AccSynthetic. + +int getModifiers(); +/** + * Answer the name of the field. + */ + +char[] getName(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IGenericMethod.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IGenericMethod.java new file mode 100644 index 0000000..87d27ad --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IGenericMethod.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.env; + +public interface IGenericMethod { +/** + * Answer an int whose bits are set according the access constants + * defined by the VM spec. + */ +// We have added AccDeprecated & AccSynthetic. +int getModifiers(); + +/** + * Answer the name of the method. + * + * For a constructor, answer & for a clinit method. + */ +char[] getSelector(); + +boolean isConstructor(); + +/** + * Answer the names of the argument + * or null if the argument names are not available. + */ + +char[][] getArgumentNames(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IGenericType.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IGenericType.java new file mode 100644 index 0000000..15fe0ec --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/IGenericType.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.env; + +public interface IGenericType extends IDependent { +/** + * Answer an int whose bits are set according the access constants + * defined by the VM spec. + */ + +// We have added AccDeprecated & AccSynthetic. + +// NOTE: If the receiver represents a member type, the modifiers are extracted from its inner class attributes. + +int getModifiers(); +/** + * Answer whether the receiver contains the resolved binary form + * or the unresolved source form of the type. + */ + +boolean isBinaryType(); +boolean isClass(); +boolean isInterface(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/INameEnvironment.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/INameEnvironment.java new file mode 100644 index 0000000..3c9d42a --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/INameEnvironment.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.env; + +/** + * The name environment provides a callback API that the compiler + * can use to look up types, compilation units, and packages in the + * current environment. The name environment is passed to the compiler + * on creation. + */ +public interface INameEnvironment { +/** + * Find a type with the given compound name. + * Answer the binary form of the type if it is known to be consistent. + * Otherwise, answer the compilation unit which defines the type + * or null if the type does not exist. + * Types in the default package are specified as {{typeName}}. + * + * It is unknown whether the package containing the type actually exists. + * + * NOTE: This method can be used to find a member type using its + * internal name A$B, but the source file for A is answered if the binary + * file is inconsistent. + */ + +NameEnvironmentAnswer findType(char[][] compoundTypeName); +/** + * Find a type named in the package . + * Answer the binary form of the type if it is known to be consistent. + * Otherwise, answer the compilation unit which defines the type + * or null if the type does not exist. + * The default package is indicated by char[0][]. + * + * It is known that the package containing the type exists. + * + * NOTE: This method can be used to find a member type using its + * internal name A$B, but the source file for A is answered if the binary + * file is inconsistent. + */ + +NameEnvironmentAnswer findType(char[] typeName, char[][] packageName); +/** + * Answer whether packageName is the name of a known subpackage inside + * the package parentPackageName. A top level package is found relative to null. + * The default package is always assumed to exist. + * + * For example: + * isPackage({{java}, {awt}}, {event}); + * isPackage(null, {java}); + */ + +boolean isPackage(char[][] parentPackageName, char[] packageName); + +/** + * This method cleans the environment uo. It is responsible for releasing the memory + * and freeing resources. Passed that point, the name environment is no longer usable. + * + * A name environment can have a long life cycle, therefore it is the responsibility of + * the code which created it to decide when it is a good time to clean it up. + */ +void cleanup(); + +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/ISourceField.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/ISourceField.java new file mode 100644 index 0000000..c921aaa --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/ISourceField.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.env; + +public interface ISourceField extends IGenericField { +/** + * Answer the source end position of the field's declaration. + */ + +int getDeclarationSourceEnd(); +/** + * Answer the source start position of the field's declaration. + */ + +int getDeclarationSourceStart(); +/** + * Answer the source end position of the field's name. + */ + +int getNameSourceEnd(); +/** + * Answer the source start position of the field's name. + */ + +int getNameSourceStart(); +/** + * Answer the type name of the field. + * + * The name is a simple name or a qualified, dot separated name. + * For example, Hashtable or java.util.Hashtable. + */ + +char[] getTypeName(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/ISourceMethod.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/ISourceMethod.java new file mode 100644 index 0000000..d01394f --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/ISourceMethod.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.env; + +public interface ISourceMethod extends IGenericMethod { + +/** + * Answer the unresolved names of the argument types + * or null if the array is empty. + * + * A name is a simple name or a qualified, dot separated name. + * For example, Hashtable or java.util.Hashtable. + */ + +char[][] getArgumentTypeNames(); +/** + * Answer the source end position of the method's declaration. + */ + +int getDeclarationSourceEnd(); +/** + * Answer the source start position of the method's declaration. + */ + +int getDeclarationSourceStart(); +/** + * Answer the unresolved names of the exception types + * or null if the array is empty. + * + * A name is a simple name or a qualified, dot separated name. + * For example, Hashtable or java.util.Hashtable. + */ + +char[][] getExceptionTypeNames(); +/** + * Answer the source end position of the method's selector. + */ + +int getNameSourceEnd(); +/** + * Answer the source start position of the method's selector. + */ + +int getNameSourceStart(); +/** + * Answer the unresolved name of the return type + * or null if receiver is a constructor or clinit. + * + * The name is a simple name or a qualified, dot separated name. + * For example, Hashtable or java.util.Hashtable. + */ + +char[] getReturnTypeName(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/ISourceType.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/ISourceType.java new file mode 100644 index 0000000..ecd1ef5 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/ISourceType.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.env; + +public interface ISourceType extends IGenericType { +/** + * Answer the source end position of the type's declaration. + */ + +int getDeclarationSourceEnd(); +/** + * Answer the source start position of the type's declaration. + */ + +int getDeclarationSourceStart(); +/** + * Answer the enclosing type + * or null if the receiver is a top level type. + */ + +ISourceType getEnclosingType(); +/** + * Answer the receiver's fields or null if the array is empty. + * + * NOTE: Multiple fields with the same name can exist in the result. + */ + +ISourceField[] getFields(); +/** + * Answer the unresolved names of the receiver's imports + * or null if the array is empty. + * + * An import is a qualified, dot separated name. + * For example, java.util.Hashtable or java.lang.*. + */ + +char[][] getImports(); +/** + * Answer the unresolved names of the receiver's interfaces + * or null if the array is empty. + * + * A name is a simple name or a qualified, dot separated name. + * For example, Hashtable or java.util.Hashtable. + */ + +char[][] getInterfaceNames(); +/** + * Answer the receiver's member types + * or null if the array is empty. + */ + +ISourceType[] getMemberTypes(); +/** + * Answer the receiver's methods or null if the array is empty. + * + * NOTE: Multiple methods with the same name & parameter types can exist in the result. + */ + +ISourceMethod[] getMethods(); +/** + * Answer the simple source name of the receiver. + */ + +char[] getName(); +/** + * Answer the source end position of the type's name. + */ + +int getNameSourceEnd(); +/** + * Answer the source start position of the type's name. + */ + +int getNameSourceStart(); +/** + * Answer the qualified name of the receiver's package separated by periods + * or null if its the default package. + * + * For example, {java.util.Hashtable}. + */ + +char[] getPackageName(); +/** + * Answer the qualified name of the receiver. + * + * The name is a qualified, dot separated name. + * For example, java.util.Hashtable. + */ + +char[] getQualifiedName(); +/** + * Answer the unresolved name of the receiver's superclass + * or null if it does not have one. + * + * The name is a simple name or a qualified, dot separated name. + * For example, Hashtable or java.util.Hashtable. + */ + +char[] getSuperclassName(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/NameEnvironmentAnswer.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/NameEnvironmentAnswer.java new file mode 100644 index 0000000..7a4ec5b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/env/NameEnvironmentAnswer.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.env; + +public class NameEnvironmentAnswer { + + // only one of the three can be set + IBinaryType binaryType; + ICompilationUnit compilationUnit; + ISourceType[] sourceTypes; + + public NameEnvironmentAnswer(IBinaryType binaryType) { + this.binaryType = binaryType; + } + + public NameEnvironmentAnswer(ICompilationUnit compilationUnit) { + this.compilationUnit = compilationUnit; + } + + public NameEnvironmentAnswer(ISourceType[] sourceTypes) { + this.sourceTypes = sourceTypes; + } + + /** + * Answer the resolved binary form for the type or null if the + * receiver represents a compilation unit or source type. + */ + public IBinaryType getBinaryType() { + return binaryType; + } + + /** + * Answer the compilation unit or null if the + * receiver represents a binary or source type. + */ + public ICompilationUnit getCompilationUnit() { + return compilationUnit; + } + + /** + * Answer the unresolved source forms for the type or null if the + * receiver represents a compilation unit or binary type. + * + * Multiple source forms can be answered in case the originating compilation unit did contain + * several type at once. Then the first type is guaranteed to be the requested type. + */ + public ISourceType[] getSourceTypes() { + return sourceTypes; + } + + /** + * Answer whether the receiver contains the resolved binary form of the type. + */ + public boolean isBinaryType() { + return binaryType != null; + } + + /** + * Answer whether the receiver contains the compilation unit which defines the type. + */ + public boolean isCompilationUnit() { + return compilationUnit != null; + } + + /** + * Answer whether the receiver contains the unresolved source form of the type. + */ + public boolean isSourceType() { + return sourceTypes != null; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/ConditionalFlowInfo.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/ConditionalFlowInfo.java new file mode 100644 index 0000000..5567650 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/ConditionalFlowInfo.java @@ -0,0 +1,127 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.flow; + +import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding; + +/** + * Record conditional initialization status during definite assignment analysis + * + */ +public class ConditionalFlowInfo extends FlowInfo { + public FlowInfo initsWhenTrue; + public FlowInfo initsWhenFalse; +ConditionalFlowInfo(FlowInfo initsWhenTrue, FlowInfo initsWhenFalse){ + this.initsWhenTrue = initsWhenTrue; + this.initsWhenFalse = initsWhenFalse; +} +public UnconditionalFlowInfo addInitializationsFrom(UnconditionalFlowInfo otherInits) { + return unconditionalInits().addInitializationsFrom(otherInits); +} +public UnconditionalFlowInfo addPotentialInitializationsFrom(UnconditionalFlowInfo otherInits) { + return unconditionalInits().addPotentialInitializationsFrom(otherInits); +} +public FlowInfo asNegatedCondition() { + FlowInfo extra = initsWhenTrue; + initsWhenTrue = initsWhenFalse; + initsWhenFalse = extra; + return this; +} +public FlowInfo copy() { + return new ConditionalFlowInfo(initsWhenTrue.copy(), initsWhenFalse.copy()); +} +public FlowInfo initsWhenFalse() { + return initsWhenFalse; +} +public FlowInfo initsWhenTrue() { + return initsWhenTrue; +} +/** + * Check status of definite assignment for a field. + */ +public boolean isDefinitelyAssigned(FieldBinding field) { + return initsWhenTrue.isDefinitelyAssigned(field) + && initsWhenFalse.isDefinitelyAssigned(field); + +} +/** + * Check status of definite assignment for a local variable. + */ +public boolean isDefinitelyAssigned(LocalVariableBinding local) { + return initsWhenTrue.isDefinitelyAssigned(local) + && initsWhenFalse.isDefinitelyAssigned(local); + +} +public boolean isFakeReachable(){ + return unconditionalInits().isFakeReachable(); + //should maybe directly be: false +} +/** + * Check status of potential assignment for a field. + */ +public boolean isPotentiallyAssigned(FieldBinding field) { + return initsWhenTrue.isPotentiallyAssigned(field) + || initsWhenFalse.isPotentiallyAssigned(field); + +} +/** + * Check status of potential assignment for a local variable. + */ +public boolean isPotentiallyAssigned(LocalVariableBinding local) { + return initsWhenTrue.isPotentiallyAssigned(local) + || initsWhenFalse.isPotentiallyAssigned(local); + +} +/** + * Record a field got definitely assigned. + */ +public void markAsDefinitelyAssigned(FieldBinding field) { + initsWhenTrue.markAsDefinitelyAssigned(field); + initsWhenFalse.markAsDefinitelyAssigned(field); +} +/** + * Record a field got definitely assigned. + */ +public void markAsDefinitelyAssigned(LocalVariableBinding local) { + initsWhenTrue.markAsDefinitelyAssigned(local); + initsWhenFalse.markAsDefinitelyAssigned(local); +} +/** + * Clear the initialization info for a field + */ +public void markAsDefinitelyNotAssigned(FieldBinding field) { + initsWhenTrue.markAsDefinitelyNotAssigned(field); + initsWhenFalse.markAsDefinitelyNotAssigned(field); +} +/** + * Clear the initialization info for a local variable + */ +public void markAsDefinitelyNotAssigned(LocalVariableBinding local) { + initsWhenTrue.markAsDefinitelyNotAssigned(local); + initsWhenFalse.markAsDefinitelyNotAssigned(local); +} +public FlowInfo markAsFakeReachable(boolean isFakeReachable) { + initsWhenTrue.markAsFakeReachable(isFakeReachable); + initsWhenFalse.markAsFakeReachable(isFakeReachable); + return this; +} +public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) { + return unconditionalInits().mergedWith(otherInits); +} +public String toString() { + return "FlowInfo"; //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-2$ +} +public UnconditionalFlowInfo unconditionalInits() { + return initsWhenTrue.unconditionalInits().copy() + .mergedWith(initsWhenFalse.unconditionalInits()); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/ExceptionHandlingFlowContext.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/ExceptionHandlingFlowContext.java new file mode 100644 index 0000000..2ee8ae7 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/ExceptionHandlingFlowContext.java @@ -0,0 +1,187 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.flow; + +import java.util.ArrayList; + +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.ast.TryStatement; +import net.sourceforge.phpdt.internal.compiler.codegen.ObjectCache; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.Scope; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; + +/** + * Reflects the context of code analysis, keeping track of enclosing + * try statements, exception handlers, etc... + */ +public class ExceptionHandlingFlowContext extends FlowContext { + + ReferenceBinding[] handledExceptions; + + public final static int BitCacheSize = 32; // 32 bits per int + int[] isReached; + int[] isNeeded; + UnconditionalFlowInfo[] initsOnExceptions; + ObjectCache indexes = new ObjectCache(); + boolean isMethodContext; + + public UnconditionalFlowInfo initsOnReturn; + + // for dealing with anonymous constructor thrown exceptions + public ArrayList extendedExceptions; + + public ExceptionHandlingFlowContext( + FlowContext parent, + AstNode associatedNode, + ReferenceBinding[] handledExceptions, + BlockScope scope, + UnconditionalFlowInfo flowInfo) { + + super(parent, associatedNode); + isMethodContext = scope == scope.methodScope(); + this.handledExceptions = handledExceptions; + int count = handledExceptions.length, cacheSize = (count / BitCacheSize) + 1; + this.isReached = new int[cacheSize]; // none is reached by default + this.isNeeded = new int[cacheSize]; // none is needed by default + this.initsOnExceptions = new UnconditionalFlowInfo[count]; + for (int i = 0; i < count; i++) { + this.indexes.put(handledExceptions[i], i); // key type -> value index + boolean isUnchecked = + (scope.compareUncheckedException(handledExceptions[i]) != NotRelated); + int cacheIndex = i / BitCacheSize, bitMask = 1 << (i % BitCacheSize); + if (isUnchecked) { + isReached[cacheIndex] |= bitMask; + this.initsOnExceptions[i] = flowInfo.copy().unconditionalInits(); + } else { + this.initsOnExceptions[i] = FlowInfo.DeadEnd; + } + } + System.arraycopy(this.isReached, 0, this.isNeeded, 0, cacheSize); + this.initsOnReturn = FlowInfo.DeadEnd; + } + + public void complainIfUnusedExceptionHandlers( + AstNode[] exceptionHandlers, + BlockScope scope, + TryStatement tryStatement) { + // report errors for unreachable exception handlers + for (int i = 0, count = handledExceptions.length; i < count; i++) { + int index = indexes.get(handledExceptions[i]); + int cacheIndex = index / BitCacheSize; + int bitMask = 1 << (index % BitCacheSize); + if ((isReached[cacheIndex] & bitMask) == 0) { + scope.problemReporter().unreachableExceptionHandler( + handledExceptions[index], + exceptionHandlers[index]); + } else { + if ((isNeeded[cacheIndex] & bitMask) == 0) { + scope.problemReporter().maskedExceptionHandler( + handledExceptions[index], + exceptionHandlers[index]); + } + } + } + // will optimized out unnecessary catch block during code gen + tryStatement.preserveExceptionHandler = isNeeded; + } + + public String individualToString() { + + StringBuffer buffer = new StringBuffer("Exception flow context"); //$NON-NLS-1$ + int length = handledExceptions.length; + for (int i = 0; i < length; i++) { + int cacheIndex = i / BitCacheSize; + int bitMask = 1 << (i % BitCacheSize); + buffer.append('[').append(handledExceptions[i].readableName()); + if ((isReached[cacheIndex] & bitMask) != 0) { + if ((isNeeded[cacheIndex] & bitMask) == 0) { + buffer.append("-masked"); //$NON-NLS-1$ + } else { + buffer.append("-reached"); //$NON-NLS-1$ + } + } else { + buffer.append("-not reached"); //$NON-NLS-1$ + } + buffer.append('-').append(initsOnExceptions[i].toString()).append(']'); + } + return buffer.toString(); + } + + public UnconditionalFlowInfo initsOnException(ReferenceBinding exceptionType) { + + int index; + if ((index = indexes.get(exceptionType)) < 0) { + return FlowInfo.DeadEnd; + } + return initsOnExceptions[index]; + } + + public void recordHandlingException( + ReferenceBinding exceptionType, + UnconditionalFlowInfo flowInfo, + TypeBinding raisedException, + AstNode invocationSite, + boolean wasAlreadyDefinitelyCaught) { + + int index = indexes.get(exceptionType); + // if already flagged as being reached (unchecked exception handler) + int cacheIndex = index / BitCacheSize; + int bitMask = 1 << (index % BitCacheSize); + if (!wasAlreadyDefinitelyCaught) { + this.isNeeded[cacheIndex] |= bitMask; + } + this.isReached[cacheIndex] |= bitMask; + initsOnExceptions[index] = + initsOnExceptions[index] == FlowInfo.DeadEnd + ? flowInfo.copy().unconditionalInits() + : initsOnExceptions[index].mergedWith(flowInfo); + } + + public void recordReturnFrom(UnconditionalFlowInfo flowInfo) { + + // record initializations which were performed at the return point + initsOnReturn = initsOnReturn.mergedWith(flowInfo); + } + + /* + * Compute a merged list of unhandled exception types (keeping only the most generic ones). + * This is necessary to add synthetic thrown exceptions for anonymous type constructors (JLS 8.6). + */ + public void mergeUnhandledException(TypeBinding newException){ + + if (this.extendedExceptions == null){ + this.extendedExceptions = new ArrayList(5); + for (int i = 0; i < this.handledExceptions.length; i++){ + this.extendedExceptions.add(this.handledExceptions[i]); + } + } + + boolean isRedundant = false; + + for(int i = this.extendedExceptions.size()-1; i >= 0; i--){ + switch(Scope.compareTypes(newException, (TypeBinding)this.extendedExceptions.get(i))){ + case MoreGeneric : + this.extendedExceptions.remove(i); + break; + case EqualOrMoreSpecific : + isRedundant = true; + break; + case NotRelated : + break; + } + } + if (!isRedundant){ + this.extendedExceptions.add(newException); + } + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/FinallyFlowContext.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/FinallyFlowContext.java new file mode 100644 index 0000000..61aec21 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/FinallyFlowContext.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.flow; + +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.ast.NameReference; +import net.sourceforge.phpdt.internal.compiler.ast.Reference; +import net.sourceforge.phpdt.internal.compiler.lookup.BindingIds; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.VariableBinding; + +/** + * Reflects the context of code analysis, keeping track of enclosing + * try statements, exception handlers, etc... + */ +public class FinallyFlowContext extends FlowContext { + + Reference finalAssignments[]; + int assignCount; + + public FinallyFlowContext(FlowContext parent, AstNode associatedNode) { + super(parent, associatedNode); + } + + /** + * Given some contextual initialization info (derived from a try block or a catch block), this + * code will check that the subroutine context does not also initialize a final variable potentially set + * redundantly. + */ + public void complainOnRedundantFinalAssignments( + FlowInfo flowInfo, + BlockScope scope) { + for (int i = 0; i < assignCount; i++) { + Reference ref; + if (((ref = finalAssignments[i]).bits & BindingIds.FIELD) != 0) { + // final field + if (flowInfo.isPotentiallyAssigned(ref.fieldBinding())) { + scope.problemReporter().duplicateInitializationOfBlankFinalField(ref.fieldBinding(), ref); + } + } else { + // final local variable + if (flowInfo + .isPotentiallyAssigned((LocalVariableBinding) ((NameReference) ref).binding)) { + scope.problemReporter().duplicateInitializationOfFinalLocal( + (LocalVariableBinding) ((NameReference) ref).binding, + (NameReference) ref); + } + } + // any reference reported at this level is removed from the parent context + // where it could also be reported again + FlowContext currentContext = parent; + while (currentContext != null) { + if (currentContext.isSubRoutine()) { + currentContext.removeFinalAssignmentIfAny(ref); + } + currentContext = currentContext.parent; + } + } + } + + public boolean isSubRoutine() { + return true; + } + + boolean recordFinalAssignment( + VariableBinding binding, + Reference finalAssignment) { + if (assignCount == 0) { + finalAssignments = new Reference[5]; + } else { + if (assignCount == finalAssignments.length) + System.arraycopy( + finalAssignments, + 0, + (finalAssignments = new Reference[assignCount * 2]), + 0, + assignCount); + }; + finalAssignments[assignCount++] = finalAssignment; + return true; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/FlowContext.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/FlowContext.java new file mode 100644 index 0000000..e92b862 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/FlowContext.java @@ -0,0 +1,449 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.flow; + +import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.ast.Reference; +import net.sourceforge.phpdt.internal.compiler.codegen.Label; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.Scope; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeConstants; +import net.sourceforge.phpdt.internal.compiler.lookup.VariableBinding; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +/** + * Reflects the context of code analysis, keeping track of enclosing + * try statements, exception handlers, etc... + */ +public class FlowContext implements TypeConstants { + public AstNode associatedNode; + public FlowContext parent; + + public final static FlowContext NotContinuableContext = + new FlowContext(null, null); + + public FlowContext(FlowContext parent, AstNode associatedNode) { + this.parent = parent; + this.associatedNode = associatedNode; + } + + public Label breakLabel() { + return null; + } + + public void checkExceptionHandlers( + TypeBinding[] raisedExceptions, + AstNode location, + FlowInfo flowInfo, + BlockScope scope) { + + // check that all the argument exception types are handled + // JDK Compatible implementation - when an exception type is thrown, + // all related catch blocks are marked as reachable... instead of those only + // until the point where it is safely handled (Smarter - see comment at the end) + int remainingCount; // counting the number of remaining unhandled exceptions + int raisedCount; // total number of exceptions raised + if ((raisedExceptions == null) + || ((raisedCount = raisedExceptions.length) == 0)) + return; + remainingCount = raisedCount; + + // duplicate the array of raised exceptions since it will be updated + // (null replaces any handled exception) + System.arraycopy( + raisedExceptions, + 0, + (raisedExceptions = new TypeBinding[raisedCount]), + 0, + raisedCount); + FlowContext traversedContext = this; + while (traversedContext != null) { + AstNode sub; + if (((sub = traversedContext.subRoutine()) != null) && sub.cannotReturn()) { + // traversing a non-returning subroutine means that all unhandled + // exceptions will actually never get sent... + return; + } + // filter exceptions that are locally caught from the most enclosing + // try statement to the outer ones. + if (traversedContext instanceof ExceptionHandlingFlowContext) { + ExceptionHandlingFlowContext exceptionContext = + (ExceptionHandlingFlowContext) traversedContext; + ReferenceBinding[] caughtExceptions; + if ((caughtExceptions = exceptionContext.handledExceptions) != NoExceptions) { + int caughtCount = caughtExceptions.length; + boolean[] locallyCaught = new boolean[raisedCount]; // at most + + for (int caughtIndex = 0; caughtIndex < caughtCount; caughtIndex++) { + ReferenceBinding caughtException = caughtExceptions[caughtIndex]; + for (int raisedIndex = 0; raisedIndex < raisedCount; raisedIndex++) { + TypeBinding raisedException; + if ((raisedException = raisedExceptions[raisedIndex]) != null) { + switch (Scope.compareTypes(raisedException, caughtException)) { + case EqualOrMoreSpecific : + exceptionContext.recordHandlingException( + caughtException, + flowInfo.unconditionalInits(), + raisedException, + location, + locallyCaught[raisedIndex]); + // was already definitely caught ? + if (!locallyCaught[raisedIndex]) { + locallyCaught[raisedIndex] = true; + // remember that this exception has been definitely caught + remainingCount--; + } + break; + case MoreGeneric : + exceptionContext.recordHandlingException( + caughtException, + flowInfo.unconditionalInits(), + raisedException, + location, + false); + // was not caught already per construction + } + } + } + } + // remove locally caught exceptions from the remaining ones + for (int i = 0; i < raisedCount; i++) { + if (locallyCaught[i]) { + raisedExceptions[i] = null; // removed from the remaining ones. + } + } + } + // method treatment for unchecked exceptions + if (exceptionContext.isMethodContext) { + for (int i = 0; i < raisedCount; i++) { + TypeBinding raisedException; + if ((raisedException = raisedExceptions[i]) != null) { + if (scope + .areTypesCompatible(raisedException, scope.getJavaLangRuntimeException()) + || scope.areTypesCompatible(raisedException, scope.getJavaLangError())) { + remainingCount--; + raisedExceptions[i] = null; + } + } + } + // anonymous constructors are allowed to throw any exceptions (their thrown exceptions + // clause will be fixed up later as per JLS 8.6). + if (exceptionContext.associatedNode instanceof AbstractMethodDeclaration){ + AbstractMethodDeclaration method = (AbstractMethodDeclaration)exceptionContext.associatedNode; + if (method.isConstructor() && method.binding.declaringClass.isAnonymousType()){ + + for (int i = 0; i < raisedCount; i++) { + TypeBinding raisedException; + if ((raisedException = raisedExceptions[i]) != null) { + exceptionContext.mergeUnhandledException(raisedException); + } + } + return; // no need to complain, will fix up constructor exceptions + } + } + break; // not handled anywhere, thus jump to error handling + } + } + if (remainingCount == 0) + return; + traversedContext = traversedContext.parent; + } + // if reaches this point, then there are some remaining unhandled exception types. + for (int i = 0; i < raisedCount; i++) { + TypeBinding exception; + if ((exception = raisedExceptions[i]) != null) { + scope.problemReporter().unhandledException(exception, location); + } + } + } + + public void checkExceptionHandlers( + TypeBinding raisedException, + AstNode location, + FlowInfo flowInfo, + BlockScope scope) { + + // LIGHT-VERSION OF THE EQUIVALENT WITH AN ARRAY OF EXCEPTIONS + // check that all the argument exception types are handled + // JDK Compatible implementation - when an exception type is thrown, + // all related catch blocks are marked as reachable... instead of those only + // until the point where it is safely handled (Smarter - see comment at the end) + FlowContext traversedContext = this; + while (traversedContext != null) { + AstNode sub; + if (((sub = traversedContext.subRoutine()) != null) && sub.cannotReturn()) { + // traversing a non-returning subroutine means that all unhandled + // exceptions will actually never get sent... + return; + } + // filter exceptions that are locally caught from the most enclosing + // try statement to the outer ones. + if (traversedContext instanceof ExceptionHandlingFlowContext) { + ExceptionHandlingFlowContext exceptionContext = + (ExceptionHandlingFlowContext) traversedContext; + ReferenceBinding[] caughtExceptions; + if ((caughtExceptions = exceptionContext.handledExceptions) != NoExceptions) { + boolean definitelyCaught = false; + for (int caughtIndex = 0, caughtCount = caughtExceptions.length; + caughtIndex < caughtCount; + caughtIndex++) { + ReferenceBinding caughtException = caughtExceptions[caughtIndex]; + switch (Scope.compareTypes(raisedException, caughtException)) { + case EqualOrMoreSpecific : + exceptionContext.recordHandlingException( + caughtException, + flowInfo.unconditionalInits(), + raisedException, + location, + definitelyCaught); + // was it already definitely caught ? + definitelyCaught = true; + break; + case MoreGeneric : + exceptionContext.recordHandlingException( + caughtException, + flowInfo.unconditionalInits(), + raisedException, + location, + false); + // was not caught already per construction + } + } + if (definitelyCaught) + return; + } + // method treatment for unchecked exceptions + if (exceptionContext.isMethodContext) { + if (scope + .areTypesCompatible(raisedException, scope.getJavaLangRuntimeException()) + || scope.areTypesCompatible(raisedException, scope.getJavaLangError())) + return; + + // anonymous constructors are allowed to throw any exceptions (their thrown exceptions + // clause will be fixed up later as per JLS 8.6). + if (exceptionContext.associatedNode instanceof AbstractMethodDeclaration){ + AbstractMethodDeclaration method = (AbstractMethodDeclaration)exceptionContext.associatedNode; + if (method.isConstructor() && method.binding.declaringClass.isAnonymousType()){ + + exceptionContext.mergeUnhandledException(raisedException); + return; // no need to complain, will fix up constructor exceptions + } + } + break; // not handled anywhere, thus jump to error handling + } + } + traversedContext = traversedContext.parent; + } + // if reaches this point, then there are some remaining unhandled exception types. + scope.problemReporter().unhandledException(raisedException, location); + } + + public Label continueLabel() { + return null; + } + + /* + * lookup through break labels + */ + public FlowContext getTargetContextForBreakLabel(char[] labelName) { + FlowContext current = this, lastNonReturningSubRoutine = null; + while (current != null) { + if (current.isNonReturningContext()) { + lastNonReturningSubRoutine = current; + } + char[] currentLabelName; + if (((currentLabelName = current.labelName()) != null) + && CharOperation.equals(currentLabelName, labelName)) { + if (lastNonReturningSubRoutine == null) { + return current; + } else { + return lastNonReturningSubRoutine; + } + } + current = current.parent; + } + // not found + return null; + } + + /* + * lookup through continue labels + */ + public FlowContext getTargetContextForContinueLabel(char[] labelName) { + FlowContext current = this, + lastContinuable = null, + lastNonReturningSubRoutine = null; + while (current != null) { + if (current.isNonReturningContext()) { + lastNonReturningSubRoutine = current; + } else { + if (current.isContinuable()) { + lastContinuable = current; + } + } + char[] currentLabelName; + if (((currentLabelName = current.labelName()) != null) + && CharOperation.equals(currentLabelName, labelName)) { + if ((lastContinuable != null) + && (current.associatedNode.concreteStatement() + == lastContinuable.associatedNode)) { + if (lastNonReturningSubRoutine == null) { + return lastContinuable; + } else { + return lastNonReturningSubRoutine; + } + } else { + // label is found, but not a continuable location + return NotContinuableContext; + } + } + current = current.parent; + } + // not found + return null; + } + + /* + * lookup a default break through breakable locations + */ + public FlowContext getTargetContextForDefaultBreak() { + FlowContext current = this, lastNonReturningSubRoutine = null; + while (current != null) { + if (current.isNonReturningContext()) { + lastNonReturningSubRoutine = current; + } + if (current.isBreakable()) { + if (lastNonReturningSubRoutine == null) { + return current; + } else { + return lastNonReturningSubRoutine; + } + } + current = current.parent; + } + // not found + return null; + } + + /* + * lookup a default continue amongst continuable locations + */ + public FlowContext getTargetContextForDefaultContinue() { + FlowContext current = this, lastNonReturningSubRoutine = null; + while (current != null) { + if (current.isNonReturningContext()) { + lastNonReturningSubRoutine = current; + } + if (current.isContinuable()) { + if (lastNonReturningSubRoutine == null) { + return current; + } else { + return lastNonReturningSubRoutine; + } + } + current = current.parent; + } + // not found + return null; + } + + public String individualToString() { + return "Flow context"; //$NON-NLS-1$ + } + + public FlowInfo initsOnBreak() { + return FlowInfo.DeadEnd; + } + + public boolean isBreakable() { + return false; + } + + public boolean isContinuable() { + return false; + } + + public boolean isNonReturningContext() { + return false; + } + + public boolean isSubRoutine() { + return false; + } + + public char[] labelName() { + return null; + } + + public void recordBreakFrom(FlowInfo flowInfo) { + } + + public void recordContinueFrom(FlowInfo flowInfo) { + } + + boolean recordFinalAssignment( + VariableBinding variable, + Reference finalReference) { + return true; // keep going + } + + public void recordReturnFrom(UnconditionalFlowInfo flowInfo) { + } + + public void recordSettingFinal( + VariableBinding variable, + Reference finalReference) { + // for initialization inside looping statement that effectively loops + FlowContext context = this; + while (context != null) { + if (!context.recordFinalAssignment(variable, finalReference)) { + break; // no need to keep going + } + context = context.parent; + } + } + + void removeFinalAssignmentIfAny(Reference reference) { + } + + public AstNode subRoutine() { + return null; + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + FlowContext current = this; + int parentsCount = 0; + while ((current = current.parent) != null) { + parentsCount++; + } + FlowContext[] parents = new FlowContext[parentsCount + 1]; + current = this; + int index = parentsCount; + while (index >= 0) { + parents[index--] = current; + current = current.parent; + } + for (int i = 0; i < parentsCount; i++) { + for (int j = 0; j < i; j++) + buffer.append('\t'); + buffer.append(parents[i].individualToString()).append('\n'); + } + buffer.append('*'); + for (int j = 0; j < parentsCount + 1; j++) + buffer.append('\t'); + buffer.append(individualToString()).append('\n'); + return buffer.toString(); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/FlowInfo.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/FlowInfo.java new file mode 100644 index 0000000..b5ec0be --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/FlowInfo.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.flow; + +import net.sourceforge.phpdt.internal.compiler.ast.Statement; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding; + +public abstract class FlowInfo { + public static final UnconditionalFlowInfo DeadEnd = new UnconditionalFlowInfo(); // Represents a dead branch status of initialization +abstract public UnconditionalFlowInfo addInitializationsFrom(UnconditionalFlowInfo otherInits); +abstract public UnconditionalFlowInfo addPotentialInitializationsFrom(UnconditionalFlowInfo otherInits); +public FlowInfo asNegatedCondition() { + return this; +} +public boolean complainIfUnreachable(Statement statement, BlockScope scope) { + // Report an error if necessary + + return false; +} +public static FlowInfo conditional(FlowInfo initsWhenTrue, FlowInfo initsWhenFalse){ + // if (initsWhenTrue.equals(initsWhenFalse)) return initsWhenTrue; -- could optimize if #equals is defined + return new ConditionalFlowInfo(initsWhenTrue, initsWhenFalse); +} +abstract public FlowInfo copy(); +public static UnconditionalFlowInfo initial(int maxFieldCount) { + UnconditionalFlowInfo info = new UnconditionalFlowInfo(); + info.maxFieldCount = maxFieldCount; + return info; +} +abstract public FlowInfo initsWhenFalse(); +abstract public FlowInfo initsWhenTrue(); +final public boolean isDeadEnd() { + return this == DeadEnd; +} +/** + * Check status of definite assignment for a field. + */ + abstract public boolean isDefinitelyAssigned(FieldBinding field); +/** + * Check status of definite assignment for a local. + */ +public abstract boolean isDefinitelyAssigned(LocalVariableBinding local); +abstract public boolean isFakeReachable(); +/** + * Check status of potential assignment for a field. + */ + abstract public boolean isPotentiallyAssigned(FieldBinding field); +/** + * Check status of potential assignment for a local variable. + */ + abstract public boolean isPotentiallyAssigned(LocalVariableBinding field); +/** + * Record a field got definitely assigned. + */ +abstract public void markAsDefinitelyAssigned(FieldBinding field); +/** + * Record a local got definitely assigned. + */ +abstract public void markAsDefinitelyAssigned(LocalVariableBinding local); +/** + * Clear the initialization info for a field + */ +abstract public void markAsDefinitelyNotAssigned(FieldBinding field); +/** + * Clear the initialization info for a local variable + */ +abstract public void markAsDefinitelyNotAssigned(LocalVariableBinding local); +abstract public FlowInfo markAsFakeReachable(boolean isFakeReachable); +abstract public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits); +public String toString(){ + if (this == DeadEnd){ + return "FlowInfo.DeadEnd"; //$NON-NLS-1$ + } + return super.toString(); +} +abstract public UnconditionalFlowInfo unconditionalInits(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/InitializationFlowContext.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/InitializationFlowContext.java new file mode 100644 index 0000000..b5a4b2b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/InitializationFlowContext.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.flow; + +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; + +/** + * Reflects the context of code analysis, keeping track of enclosing + * try statements, exception handlers, etc... + */ +public class InitializationFlowContext extends ExceptionHandlingFlowContext { + + public int exceptionCount; + public TypeBinding[] thrownExceptions = new TypeBinding[5]; + public AstNode[] exceptionThrowers = new AstNode[5]; + public FlowInfo[] exceptionThrowerFlowInfos = new FlowInfo[5]; + + public InitializationFlowContext( + FlowContext parent, + AstNode associatedNode, + BlockScope scope) { + super( + parent, + associatedNode, + new ReferenceBinding[] { scope.getJavaLangThrowable()}, + // tolerate any kind of exception, but record them + scope, FlowInfo.DeadEnd); + } + + public void checkInitializerExceptions( + BlockScope currentScope, + FlowContext initializerContext, + FlowInfo flowInfo) { + for (int i = 0; i < exceptionCount; i++) { + initializerContext.checkExceptionHandlers( + thrownExceptions[i], + exceptionThrowers[i], + exceptionThrowerFlowInfos[i], + currentScope); + } + } + + public void recordHandlingException( + ReferenceBinding exceptionType, + UnconditionalFlowInfo flowInfo, + TypeBinding raisedException, + AstNode invocationSite, + boolean wasMasked) { + + int size = thrownExceptions.length; + if (exceptionCount == size) { + System.arraycopy( + thrownExceptions, + 0, + (thrownExceptions = new TypeBinding[size * 2]), + 0, + size); + System.arraycopy( + exceptionThrowers, + 0, + (exceptionThrowers = new AstNode[size * 2]), + 0, + size); + System.arraycopy( + exceptionThrowerFlowInfos, + 0, + (exceptionThrowerFlowInfos = new FlowInfo[size * 2]), + 0, + size); + } + thrownExceptions[exceptionCount] = raisedException; + exceptionThrowers[exceptionCount] = invocationSite; + exceptionThrowerFlowInfos[exceptionCount++] = flowInfo.copy(); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/InsideSubRoutineFlowContext.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/InsideSubRoutineFlowContext.java new file mode 100644 index 0000000..3ed888f --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/InsideSubRoutineFlowContext.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.flow; + +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; + +/** + * Reflects the context of code analysis, keeping track of enclosing + * try statements, exception handlers, etc... + */ +public class InsideSubRoutineFlowContext extends FlowContext { + + public UnconditionalFlowInfo initsOnReturn; + + public InsideSubRoutineFlowContext( + FlowContext parent, + AstNode associatedNode) { + super(parent, associatedNode); + this.initsOnReturn = FlowInfo.DeadEnd; + } + + public boolean isNonReturningContext() { + return associatedNode.cannotReturn(); + } + + public AstNode subRoutine() { + return associatedNode; + } + + public void recordReturnFrom(UnconditionalFlowInfo flowInfo) { + // record initializations which were performed at the return point + initsOnReturn = initsOnReturn.mergedWith(flowInfo); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/LabelFlowContext.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/LabelFlowContext.java new file mode 100644 index 0000000..5d87f1c --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/LabelFlowContext.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.flow; + +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.codegen.Label; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +/** + * Reflects the context of code analysis, keeping track of enclosing + * try statements, exception handlers, etc... + */ +public class LabelFlowContext extends SwitchFlowContext { + public char[] labelName; + public LabelFlowContext( + FlowContext parent, + AstNode associatedNode, + char[] labelName, + Label breakLabel, + BlockScope scope) { + super(parent, associatedNode, breakLabel); + this.labelName = labelName; + checkLabelValidity(scope); + } + + void checkLabelValidity(BlockScope scope) { + // check if label was already defined above + FlowContext current = parent; + while (current != null) { + char[] currentLabelName; + if (((currentLabelName = current.labelName()) != null) + && CharOperation.equals(currentLabelName, labelName)) { + scope.problemReporter().alreadyDefinedLabel(labelName, associatedNode); + } + current = current.parent; + } + } + + public String individualToString() { + return "Label flow context [label:" + String.valueOf(labelName) + "]"; //$NON-NLS-2$ //$NON-NLS-1$ + } + + public char[] labelName() { + return labelName; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/LoopingFlowContext.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/LoopingFlowContext.java new file mode 100644 index 0000000..5034c03 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/LoopingFlowContext.java @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.flow; + +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.ast.NameReference; +import net.sourceforge.phpdt.internal.compiler.ast.Reference; +import net.sourceforge.phpdt.internal.compiler.codegen.Label; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.Scope; +import net.sourceforge.phpdt.internal.compiler.lookup.VariableBinding; + +/** + * Reflects the context of code analysis, keeping track of enclosing + * try statements, exception handlers, etc... + */ +public class LoopingFlowContext extends SwitchFlowContext { + public Label continueLabel; + public UnconditionalFlowInfo initsOnContinue = FlowInfo.DeadEnd; + Reference finalAssignments[]; + VariableBinding finalVariables[]; + int assignCount = 0; + Scope associatedScope; + public LoopingFlowContext( + FlowContext parent, + AstNode associatedNode, + Label breakLabel, + Label continueLabel, + Scope associatedScope) { + super(parent, associatedNode, breakLabel); + this.continueLabel = continueLabel; + this.associatedScope = associatedScope; + } + + public void complainOnFinalAssignmentsInLoop( + BlockScope scope, + FlowInfo flowInfo) { + for (int i = 0; i < assignCount; i++) { + VariableBinding variable; + if ((variable = finalVariables[i]) != null) { + boolean complained; // remember if have complained on this final assignment + if (variable instanceof FieldBinding) { + if (complained = flowInfo.isPotentiallyAssigned((FieldBinding) variable)) { + scope.problemReporter().duplicateInitializationOfBlankFinalField( + (FieldBinding) variable, + (NameReference) finalAssignments[i]); + } + } else { + if (complained = + flowInfo.isPotentiallyAssigned((LocalVariableBinding) variable)) { + scope.problemReporter().duplicateInitializationOfFinalLocal( + (LocalVariableBinding) variable, + (NameReference) finalAssignments[i]); + } + } + // any reference reported at this level is removed from the parent context where it + // could also be reported again + if (complained) { + FlowContext context = parent; + while (context != null) { + context.removeFinalAssignmentIfAny(finalAssignments[i]); + context = context.parent; + } + } + } + } + } + + public Label continueLabel() { + return continueLabel; + } + + public String individualToString() { + return "Looping flow context"; //$NON-NLS-1$ + } + + public boolean isContinuable() { + return true; + } + + public boolean isContinuedTo() { + return initsOnContinue != FlowInfo.DeadEnd; + } + + public void recordContinueFrom(FlowInfo flowInfo) { + if (initsOnContinue == FlowInfo.DeadEnd) { + initsOnContinue = flowInfo.copy().unconditionalInits(); + } else { + // ignore if not really reachable (1FKEKRP) + if (flowInfo.isFakeReachable()) + return; + initsOnContinue.mergedWith(flowInfo.unconditionalInits()); + }; + } + + boolean recordFinalAssignment( + VariableBinding binding, + Reference finalAssignment) { + // do not consider variables which are defined inside this loop + if (binding instanceof LocalVariableBinding) { + Scope scope = ((LocalVariableBinding) binding).declaringScope; + while ((scope = scope.parent) != null) { + if (scope == associatedScope) + return false; + } + } + if (assignCount == 0) { + finalAssignments = new Reference[5]; + finalVariables = new VariableBinding[5]; + } else { + if (assignCount == finalAssignments.length) + System.arraycopy( + finalAssignments, + 0, + (finalAssignments = new Reference[assignCount * 2]), + 0, + assignCount); + System.arraycopy( + finalVariables, + 0, + (finalVariables = new VariableBinding[assignCount * 2]), + 0, + assignCount); + }; + finalAssignments[assignCount] = finalAssignment; + finalVariables[assignCount++] = binding; + return true; + } + + void removeFinalAssignmentIfAny(Reference reference) { + for (int i = 0; i < assignCount; i++) { + if (finalAssignments[i] == reference) { + finalAssignments[i] = null; + finalVariables[i] = null; + return; + } + } + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/SwitchFlowContext.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/SwitchFlowContext.java new file mode 100644 index 0000000..e156adb --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/SwitchFlowContext.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.flow; + +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.codegen.Label; + +/** + * Reflects the context of code analysis, keeping track of enclosing + * try statements, exception handlers, etc... + */ +public class SwitchFlowContext extends FlowContext { + public Label breakLabel; + public UnconditionalFlowInfo initsOnBreak = FlowInfo.DeadEnd; + + public SwitchFlowContext( + FlowContext parent, + AstNode associatedNode, + Label breakLabel) { + super(parent, associatedNode); + this.breakLabel = breakLabel; + } + + public Label breakLabel() { + return breakLabel; + } + + public String individualToString() { + return "Switch flow context"; //$NON-NLS-1$ + } + + public boolean isBreakable() { + return true; + } + + public void recordBreakFrom(FlowInfo flowInfo) { + if (initsOnBreak == FlowInfo.DeadEnd) { + initsOnBreak = flowInfo.copy().unconditionalInits(); + } else { + // ignore if not really reachable (1FKEKRP) + if (flowInfo.isFakeReachable()) + return; + initsOnBreak.mergedWith(flowInfo.unconditionalInits()); + }; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/UnconditionalFlowInfo.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/UnconditionalFlowInfo.java new file mode 100644 index 0000000..045e723 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/UnconditionalFlowInfo.java @@ -0,0 +1,439 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.flow; + +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.ast.Statement; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding; + +/** + * Record initialization status during definite assignment analysis + * + * No caching of pre-allocated instances. + */ +public class UnconditionalFlowInfo extends FlowInfo { + public long definiteInits; + long potentialInits; + public long extraDefiniteInits[]; + long extraPotentialInits[]; + public boolean isFakeReachable; + public int maxFieldCount; + + // Constants + public static final int BitCacheSize = 64; // 64 bits in a long. +UnconditionalFlowInfo() { +} +public UnconditionalFlowInfo addInitializationsFrom(UnconditionalFlowInfo otherInits) { + + // unions of both sets of initialization - used for try/finally + if (this == DeadEnd) + return this; + if (otherInits == DeadEnd) + return this; + + // union of definitely assigned variables, + definiteInits |= otherInits.definiteInits; + // union of potentially set ones + potentialInits |= otherInits.potentialInits; + + // treating extra storage + if (extraDefiniteInits != null) { + if (otherInits.extraDefiniteInits != null) { + // both sides have extra storage + int i = 0, length, otherLength; + if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) { + // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?) + System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength]), 0, length); + System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, length); + while (i < length) { + extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i]; + extraPotentialInits[i] |= otherInits.extraPotentialInits[i++]; + } + while (i < otherLength) { + extraPotentialInits[i] = otherInits.extraPotentialInits[i++]; + } + } else { + // current storage is longer + while (i < otherLength) { + extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i]; + extraPotentialInits[i] |= otherInits.extraPotentialInits[i++]; + } + while (i < length) + extraDefiniteInits[i++] = 0; + } + } else { + // no extra storage on otherInits + } + } else + if (otherInits.extraDefiniteInits != null) { + // no storage here, but other has extra storage. + int otherLength; + System.arraycopy(otherInits.extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length]), 0, otherLength); + System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength); + } + return this; +} +public UnconditionalFlowInfo addPotentialInitializationsFrom(UnconditionalFlowInfo otherInits) { + + // unions of both sets of initialization - used for try/finally + if (this == DeadEnd){ + return this; + } + if (otherInits == DeadEnd){ + return this; + } + // union of potentially set ones + potentialInits |= otherInits.potentialInits; + + // treating extra storage + if (extraDefiniteInits != null) { + if (otherInits.extraDefiniteInits != null) { + // both sides have extra storage + int i = 0, length, otherLength; + if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) { + // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?) + System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength]), 0, length); + System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, length); + while (i < length) { + extraPotentialInits[i] |= otherInits.extraPotentialInits[i++]; + } + while (i < otherLength) { + extraPotentialInits[i] = otherInits.extraPotentialInits[i++]; + } + } else { + // current storage is longer + while (i < otherLength) { + extraPotentialInits[i] |= otherInits.extraPotentialInits[i++]; + } + } + } + } else + if (otherInits.extraDefiniteInits != null) { + // no storage here, but other has extra storage. + int otherLength; + extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length]; + System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength); + } + return this; +} +public boolean complainIfUnreachable(Statement statement, BlockScope scope) { + // Report an error if necessary + + boolean isDeadEnd; + if ((isDeadEnd = (this == DeadEnd)) || isFakeReachable) { + statement.bits &= ~AstNode.IsReachableMASK; + /* EXTRA REFERENCE RECORDING + statement.recordUnreachableReferences(scope.referenceType()); // scopes cannot have an enclosingMethod slot since there are class scopes + */ + if (isDeadEnd) + scope.problemReporter().unreachableCode(statement); + return isDeadEnd; + } + return false; +} +/** + * Answers a copy of the current instance + */ +public FlowInfo copy() { + // do not clone the DeadEnd + if (this == DeadEnd) + return this; + + // look for an unused preallocated object + UnconditionalFlowInfo copy = new UnconditionalFlowInfo(); + + // copy slots + copy.definiteInits = definiteInits; + copy.potentialInits = potentialInits; + copy.isFakeReachable = isFakeReachable; + copy.maxFieldCount = maxFieldCount; + + if (extraDefiniteInits != null) { + int length; + System.arraycopy(extraDefiniteInits, 0, (copy.extraDefiniteInits = new long[ (length = extraDefiniteInits.length)]), 0, length); + System.arraycopy(extraPotentialInits, 0, (copy.extraPotentialInits = new long[length]), 0, length); + }; + return copy; +} +public FlowInfo initsWhenFalse() { + return this; +} +public FlowInfo initsWhenTrue() { + return this; +} +/** + * Check status of definite assignment at a given position. + * It deals with the dual representation of the InitializationInfo2: + * bits for the first 64 entries, then an array of booleans. + */ +final private boolean isDefinitelyAssigned(int position) { + // Dependant of CodeStream.isDefinitelyAssigned(..) + // id is zero-based + if (position < BitCacheSize) { + return (definiteInits & (1L << position)) != 0; // use bits + } + // use extra vector + if (extraDefiniteInits == null) + return false; // if vector not yet allocated, then not initialized + int vectorIndex; + if ((vectorIndex = (position / BitCacheSize) - 1) >= extraDefiniteInits.length) + return false; // if not enough room in vector, then not initialized + return ((extraDefiniteInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0; +} +/** + * Check status of definite assignment for a field. + */ +final public boolean isDefinitelyAssigned(FieldBinding field) { + // Dependant of CodeStream.isDefinitelyAssigned(..) + // We do not want to complain in unreachable code + if ((this == DeadEnd) || (this.isFakeReachable)) + return true; + return isDefinitelyAssigned(field.id); +} +/** + * Check status of definite assignment for a local. + */ +final public boolean isDefinitelyAssigned(LocalVariableBinding local) { + // Dependant of CodeStream.isDefinitelyAssigned(..) + // We do not want to complain in unreachable code + if ((this == DeadEnd) || (this.isFakeReachable)) + return true; + if (local.isArgument) { + return true; + } + return isDefinitelyAssigned(local.id + maxFieldCount); +} +public boolean isFakeReachable() { + return isFakeReachable; +} +/** + * Check status of potential assignment at a given position. + * It deals with the dual representation of the InitializationInfo3: + * bits for the first 64 entries, then an array of booleans. + */ +final private boolean isPotentiallyAssigned(int position) { + // id is zero-based + if (position < BitCacheSize) { + // use bits + return (potentialInits & (1L << position)) != 0; + } + // use extra vector + if (extraPotentialInits == null) + return false; // if vector not yet allocated, then not initialized + int vectorIndex; + if ((vectorIndex = (position / BitCacheSize) - 1) >= extraPotentialInits.length) + return false; // if not enough room in vector, then not initialized + return ((extraPotentialInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0; +} +/** + * Check status of definite assignment for a field. + */ +final public boolean isPotentiallyAssigned(FieldBinding field) { + // We do not want to complain in unreachable code + if ((this == DeadEnd) || (this.isFakeReachable)) + return false; + return isPotentiallyAssigned(field.id); +} +/** + * Check status of potential assignment for a local. + */ +final public boolean isPotentiallyAssigned(LocalVariableBinding local) { + // We do not want to complain in unreachable code + if ((this == DeadEnd) || (this.isFakeReachable)) + return false; + if (local.isArgument) { + return true; + } + return isPotentiallyAssigned(local.id + maxFieldCount); +} +/** + * Record a definite assignment at a given position. + * It deals with the dual representation of the InitializationInfo2: + * bits for the first 64 entries, then an array of booleans. + */ +final private void markAsDefinitelyAssigned(int position) { + if (this != DeadEnd) { + + // position is zero-based + if (position < BitCacheSize) { + // use bits + long mask; + definiteInits |= (mask = 1L << position); + potentialInits |= mask; + } else { + // use extra vector + int vectorIndex = (position / BitCacheSize) - 1; + if (extraDefiniteInits == null) { + int length; + extraDefiniteInits = new long[length = vectorIndex + 1]; + extraPotentialInits = new long[length]; + } else { + int oldLength; // might need to grow the arrays + if (vectorIndex >= (oldLength = extraDefiniteInits.length)) { + System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[vectorIndex + 1]), 0, oldLength); + System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[vectorIndex + 1]), 0, oldLength); + } + } + long mask; + extraDefiniteInits[vectorIndex] |= (mask = 1L << (position % BitCacheSize)); + extraPotentialInits[vectorIndex] |= mask; + } + } +} +/** + * Record a field got definitely assigned. + */ +public void markAsDefinitelyAssigned(FieldBinding field) { + if (this != DeadEnd) + markAsDefinitelyAssigned(field.id); +} +/** + * Record a local got definitely assigned. + */ +public void markAsDefinitelyAssigned(LocalVariableBinding local) { + if (this != DeadEnd) + markAsDefinitelyAssigned(local.id + maxFieldCount); +} +/** + * Clear initialization information at a given position. + * It deals with the dual representation of the InitializationInfo2: + * bits for the first 64 entries, then an array of booleans. + */ +final private void markAsDefinitelyNotAssigned(int position) { + if (this != DeadEnd) { + + // position is zero-based + if (position < BitCacheSize) { + // use bits + long mask; + definiteInits &= ~(mask = 1L << position); + potentialInits &= ~mask; + } else { + // use extra vector + int vectorIndex = (position / BitCacheSize) - 1; + if (extraDefiniteInits == null) { + return; // nothing to do, it was not yet set + } else { + // might need to grow the arrays + if (vectorIndex >= extraDefiniteInits.length) { + return; // nothing to do, it was not yet set + } + } + long mask; + extraDefiniteInits[vectorIndex] &= ~(mask = 1L << (position % BitCacheSize)); + extraPotentialInits[vectorIndex] &= ~mask; + } + } +} +/** + * Clear the initialization info for a field + */ +public void markAsDefinitelyNotAssigned(FieldBinding field) { + if (this != DeadEnd) + markAsDefinitelyNotAssigned(field.id); +} +/** + * Clear the initialization info for a local variable + */ + +public void markAsDefinitelyNotAssigned(LocalVariableBinding local) { + if (this != DeadEnd) + markAsDefinitelyNotAssigned(local.id + maxFieldCount); +} +public FlowInfo markAsFakeReachable(boolean isFakeReachable) { + this.isFakeReachable = isFakeReachable; + return this; +} +public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) { + // updates the receiver with: + // - intersection of definitely assigned variables, + // - union of potentially set ones + + if (this == DeadEnd) + return otherInits; + if (otherInits == DeadEnd) + return this; + + // if one branch is not fake reachable, then the merged one is reachable + if (!otherInits.isFakeReachable()) + markAsFakeReachable(false); + + // intersection of definitely assigned variables, + definiteInits &= otherInits.definiteInits; + // union of potentially set ones + potentialInits |= otherInits.potentialInits; + + // treating extra storage + if (extraDefiniteInits != null) { + if (otherInits.extraDefiniteInits != null) { + // both sides have extra storage + int i = 0, length, otherLength; + if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) { + // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?) + System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength]), 0, length); + System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, length); + while (i < length) { + extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i]; + extraPotentialInits[i] |= otherInits.extraPotentialInits[i++]; + } + while (i < otherLength) { + extraPotentialInits[i] = otherInits.extraPotentialInits[i++]; + } + } else { + // current storage is longer + while (i < otherLength) { + extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i]; + extraPotentialInits[i] |= otherInits.extraPotentialInits[i++]; + } + while (i < length) + extraDefiniteInits[i++] = 0; + } + } else { + // no extra storage on otherInits + int i = 0, length = extraDefiniteInits.length; + while (i < length) + extraDefiniteInits[i++] = 0; + } + } else + if (otherInits.extraDefiniteInits != null) { + // no storage here, but other has extra storage. + int otherLength; + extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length]; + System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength); + } + return this; +} +/* + * Answer the total number of fields in enclosing types of a given type + */ +static int numberOfEnclosingFields(ReferenceBinding type){ + int count = 0; + type = type.enclosingType(); + while(type != null) { + count += type.fieldCount(); + type = type.enclosingType(); + } + return count; +} +public String toString(){ + if (this == DeadEnd){ + return "FlowInfo.DeadEnd"; //$NON-NLS-1$ + } + return "FlowInfo"; //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-2$ +} +public UnconditionalFlowInfo unconditionalInits() { + // also see conditional inits, where it requests them to merge + return this; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/BooleanConstant.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/BooleanConstant.java new file mode 100644 index 0000000..50ab4f1 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/BooleanConstant.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.impl; + +public class BooleanConstant extends Constant { + boolean value; + + +public BooleanConstant(boolean value) { + this.value = value; +} +public boolean booleanValue() { + return (boolean) value; +} +public String stringValue() { + //spec 15.17.11 + + String s = new Boolean(value).toString() ; + if (s == null) + return "null"; //$NON-NLS-1$ + else + return s; +} +public String toString(){ + + return "(boolean)" + value ; } //$NON-NLS-1$ +public int typeID() { + return T_boolean; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/ByteConstant.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/ByteConstant.java new file mode 100644 index 0000000..bc3e345 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/ByteConstant.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.impl; + +public class ByteConstant extends Constant { + byte value; +public ByteConstant(byte value) { + this.value = value; +} +public byte byteValue() { + return (byte) value; +} +public char charValue() { + return (char) value; +} +public double doubleValue() { + return (double) value; +} +public float floatValue() { + return (float) value; +} +public int intValue() { + return (int) value; +} +public long longValue() { + return (long) value; +} +public short shortValue() { + return (short) value; +} +public String stringValue() { + //spec 15.17.11 + + String s = new Integer(value).toString() ; + if (s == null) + return "null"; //$NON-NLS-1$ + else + return s; +} +public String toString(){ + + return "(byte)" + value ; } //$NON-NLS-1$ +public int typeID() { + return T_byte; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/CharConstant.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/CharConstant.java new file mode 100644 index 0000000..7fa4d5f --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/CharConstant.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.impl; + +public class CharConstant extends Constant { + char value; +public CharConstant(char value) { + this.value = value; +} +public byte byteValue() { + return (byte) value; +} +public char charValue() { + return (char) value; +} +public double doubleValue() { + return (double) value; +} +public float floatValue() { + return (float) value; +} +public int intValue() { + return (int) value; +} +public long longValue() { + return (long) value; +} +public short shortValue() { + return (short) value; +} +public String stringValue() { + //spec 15.17.11 + + String s = new Character(value).toString() ; + if (s == null) + return "null"; //$NON-NLS-1$ + else + return s; +} +public String toString(){ + + return "(char)" + value ; } //$NON-NLS-1$ +public int typeID() { + return T_char; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/CompilerOptions.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/CompilerOptions.java new file mode 100644 index 0000000..4c761f4 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/CompilerOptions.java @@ -0,0 +1,619 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.impl; + +import java.io.ByteArrayInputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.util.Map; + +import net.sourceforge.phpdt.internal.compiler.Compiler; +import net.sourceforge.phpdt.internal.compiler.lookup.ProblemReasons; +import net.sourceforge.phpdt.internal.compiler.problem.ProblemSeverities; + + +public class CompilerOptions implements ProblemReasons, ProblemSeverities { + + /** + * Option IDs + */ + public static final String OPTION_LocalVariableAttribute = "org.eclipse.jdt.core.compiler.debug.localVariable"; //$NON-NLS-1$ + public static final String OPTION_LineNumberAttribute = "org.eclipse.jdt.core.compiler.debug.lineNumber"; //$NON-NLS-1$ + public static final String OPTION_SourceFileAttribute = "org.eclipse.jdt.core.compiler.debug.sourceFile"; //$NON-NLS-1$ + public static final String OPTION_PreserveUnusedLocal = "org.eclipse.jdt.core.compiler.codegen.unusedLocal"; //$NON-NLS-1$ + public static final String OPTION_ReportUnreachableCode = "org.eclipse.jdt.core.compiler.problem.unreachableCode"; //$NON-NLS-1$ + public static final String OPTION_ReportInvalidImport = "org.eclipse.jdt.core.compiler.problem.invalidImport"; //$NON-NLS-1$ + public static final String OPTION_ReportMethodWithConstructorName = "org.eclipse.jdt.core.compiler.problem.methodWithConstructorName"; //$NON-NLS-1$ + public static final String OPTION_ReportOverridingPackageDefaultMethod = "org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod"; //$NON-NLS-1$ + public static final String OPTION_ReportDeprecation = "org.eclipse.jdt.core.compiler.problem.deprecation"; //$NON-NLS-1$ + public static final String OPTION_ReportHiddenCatchBlock = "org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock"; //$NON-NLS-1$ + public static final String OPTION_ReportUnusedLocal = "org.eclipse.jdt.core.compiler.problem.unusedLocal"; //$NON-NLS-1$ + public static final String OPTION_ReportUnusedParameter = "org.eclipse.jdt.core.compiler.problem.unusedParameter"; //$NON-NLS-1$ + public static final String OPTION_ReportUnusedImport = "org.eclipse.jdt.core.compiler.problem.unusedImport"; //$NON-NLS-1$ + public static final String OPTION_ReportSyntheticAccessEmulation = "org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation"; //$NON-NLS-1$ + public static final String OPTION_ReportNonExternalizedStringLiteral = "org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral"; //$NON-NLS-1$ + public static final String OPTION_Source = "org.eclipse.jdt.core.compiler.source"; //$NON-NLS-1$ + public static final String OPTION_TargetPlatform = "org.eclipse.jdt.core.compiler.codegen.targetPlatform"; //$NON-NLS-1$ + public static final String OPTION_ReportAssertIdentifier = "org.eclipse.jdt.core.compiler.problem.assertIdentifier"; //$NON-NLS-1$ + public static final String OPTION_Compliance = "org.eclipse.jdt.core.compiler.compliance"; //$NON-NLS-1$ + public static final String OPTION_Encoding = "org.eclipse.jdt.core.encoding"; //$NON-NLS-1$ + public static final String OPTION_MaxProblemPerUnit = "org.eclipse.jdt.core.compiler.maxProblemPerUnit"; //$NON-NLS-1$ + + /* should surface ??? */ + public static final String OPTION_PrivateConstructorAccess = "org.eclipse.jdt.core.compiler.codegen.constructorAccessEmulation"; //$NON-NLS-1$ + + /** + * Possible values for configurable options + */ + public static final String GENERATE = "generate";//$NON-NLS-1$ + public static final String DO_NOT_GENERATE = "do not generate"; //$NON-NLS-1$ + public static final String PRESERVE = "preserve"; //$NON-NLS-1$ + public static final String OPTIMIZE_OUT = "optimize out"; //$NON-NLS-1$ + public static final String VERSION_1_1 = "1.1"; //$NON-NLS-1$ + public static final String VERSION_1_2 = "1.2"; //$NON-NLS-1$ + public static final String VERSION_1_3 = "1.3"; //$NON-NLS-1$ + public static final String VERSION_1_4 = "1.4"; //$NON-NLS-1$ + public static final String ERROR = "error"; //$NON-NLS-1$ + public static final String WARNING = "warning"; //$NON-NLS-1$ + public static final String IGNORE = "ignore"; //$NON-NLS-1$ + + /** + * Bit mask for configurable problems (error/warning threshold) + */ + public static final int UnreachableCode = 0x100; + public static final int ImportProblem = 0x400; + public static final int MethodWithConstructorName = 0x1000; + public static final int OverriddenPackageDefaultMethod = 0x2000; + public static final int UsingDeprecatedAPI = 0x4000; + public static final int MaskedCatchBlock = 0x8000; + public static final int UnusedLocalVariable = 0x10000; + public static final int UnusedArgument = 0x20000; + public static final int NoImplicitStringConversion = 0x40000; + public static final int AccessEmulation = 0x80000; + public static final int NonExternalizedString = 0x100000; + public static final int AssertUsedAsAnIdentifier = 0x200000; + public static final int UnusedImport = 0x400000; + + // Default severity level for handlers + public int errorThreshold = UnreachableCode | ImportProblem; + public int warningThreshold = + MethodWithConstructorName | OverriddenPackageDefaultMethod + | UsingDeprecatedAPI | MaskedCatchBlock + | AssertUsedAsAnIdentifier | NoImplicitStringConversion; + + // Debug attributes + public static final int Source = 1; // SourceFileAttribute + public static final int Lines = 2; // LineNumberAttribute + public static final int Vars = 4; // LocalVariableTableAttribute + + // By default only lines and source attributes are generated. + public int produceDebugAttributes = Lines | Source; + + + // JDK 1.1, 1.2, 1.3 or 1.4 + public static final int JDK1_1 = 0; + public static final int JDK1_2 = 1; + public static final int JDK1_3 = 2; + public static final int JDK1_4 = 3; + + public int targetJDK = JDK1_1; // default generates for JVM1.1 + public int complianceLevel = JDK1_3; // by default be compliant with 1.3 + + // toggle private access emulation for 1.2 (constr. accessor has extra arg on constructor) or 1.3 (make private constructor default access when access needed) + public boolean isPrivateConstructorAccessChangingVisibility = false; // by default, follows 1.2 + + // 1.4 feature + public boolean assertMode = false; //1.3 behavior by default + + // source encoding format + public String defaultEncoding = null; // will use the platform default encoding + + // print what unit is being processed + public boolean verbose = Compiler.DEBUG; + + // indicates if reference info is desired + public boolean produceReferenceInfo = true; + + // indicates if unused/optimizable local variables need to be preserved (debugging purpose) + public boolean preserveAllLocalVariables = false; + + // indicates whether literal expressions are inlined at parse-time or not + public boolean parseLiteralExpressionsAsConstants = true; + + // exception raised for unresolved compile errors + public String runtimeExceptionNameForCompileError = "java.lang.Error"; //$NON-NLS-1$ + + // max problems per compilation unit + public int maxProblemsPerUnit = 100; // no more than 100 problems per default + + /** + * Initializing the compiler options with defaults + */ + public CompilerOptions(){ + } + + /** + * Initializing the compiler options with external settings + */ + public CompilerOptions(Map settings){ + + if (settings == null) return; + + // filter options which are related to the compiler component + Object[] entries = settings.entrySet().toArray(); + for (int i = 0, max = entries.length; i < max; i++){ + Map.Entry entry = (Map.Entry)entries[i]; + if (!(entry.getKey() instanceof String)) continue; + if (!(entry.getValue() instanceof String)) continue; + String optionID = (String) entry.getKey(); + String optionValue = (String) entry.getValue(); + + // Local variable attribute + if(optionID.equals(OPTION_LocalVariableAttribute)){ + if (optionValue.equals(GENERATE)) { + this.produceDebugAttributes |= Vars; + } else if (optionValue.equals(DO_NOT_GENERATE)){ + this.produceDebugAttributes &= ~Vars; + } + continue; + } + // Line number attribute + if(optionID.equals(OPTION_LineNumberAttribute)) { + if (optionValue.equals(GENERATE)) { + this.produceDebugAttributes |= Lines; + } else if (optionValue.equals(DO_NOT_GENERATE)) { + this.produceDebugAttributes &= ~Lines; + } + continue; + } + // Source file attribute + if(optionID.equals(OPTION_SourceFileAttribute)) { + if (optionValue.equals(GENERATE)) { + this.produceDebugAttributes |= Source; + } else if (optionValue.equals(DO_NOT_GENERATE)) { + this.produceDebugAttributes &= ~Source; + } + continue; + } + // Preserve unused local + if(optionID.equals(OPTION_PreserveUnusedLocal)){ + if (optionValue.equals(PRESERVE)) { + this.preserveAllLocalVariables = true; + } else if (optionValue.equals(OPTIMIZE_OUT)) { + this.preserveAllLocalVariables = false; + } + continue; + } + // Report unreachable code + if(optionID.equals(OPTION_ReportUnreachableCode)){ + if (optionValue.equals(ERROR)) { + this.errorThreshold |= UnreachableCode; + this.warningThreshold &= ~UnreachableCode; + } else if (optionValue.equals(WARNING)) { + this.errorThreshold &= ~UnreachableCode; + this.warningThreshold |= UnreachableCode; + } else if (optionValue.equals(IGNORE)) { + this.errorThreshold &= ~UnreachableCode; + this.warningThreshold &= ~UnreachableCode; + } + continue; + } + // Report invalid import + if(optionID.equals(OPTION_ReportInvalidImport)){ + if (optionValue.equals(ERROR)) { + this.errorThreshold |= ImportProblem; + this.warningThreshold &= ~ImportProblem; + } else if (optionValue.equals(WARNING)) { + this.errorThreshold &= ~ImportProblem; + this.warningThreshold |= ImportProblem; + } else if (optionValue.equals(IGNORE)) { + this.errorThreshold &= ~ImportProblem; + this.warningThreshold &= ~ImportProblem; + } + continue; + } + // Define the target JDK tag for .classfiles + if(optionID.equals(OPTION_TargetPlatform)){ + if (optionValue.equals(VERSION_1_1)) { + this.targetJDK = JDK1_1; + } else if (optionValue.equals(VERSION_1_2)) { + this.targetJDK = JDK1_2; + } else if (optionValue.equals(VERSION_1_3)) { + this.targetJDK = JDK1_3; + } else if (optionValue.equals(VERSION_1_4)) { + this.targetJDK = JDK1_4; + } + continue; + } + // Define the JDK compliance level + if(optionID.equals(OPTION_Compliance)){ + if (optionValue.equals(VERSION_1_1)) { + this.complianceLevel = JDK1_1; + } else if (optionValue.equals(VERSION_1_2)) { + this.complianceLevel = JDK1_2; + } else if (optionValue.equals(VERSION_1_3)) { + this.complianceLevel = JDK1_3; + } else if (optionValue.equals(VERSION_1_4)) { + this.complianceLevel = JDK1_4; + } + continue; + } + // Private constructor access emulation (extra arg vs. visibility change) + if(optionID.equals(OPTION_PrivateConstructorAccess)){ + if (optionValue.equals(VERSION_1_1)) { + this.isPrivateConstructorAccessChangingVisibility = false; + } else if (optionValue.equals(VERSION_1_2)) { + this.isPrivateConstructorAccessChangingVisibility = false; + } else if (optionValue.equals(VERSION_1_3)) { + this.isPrivateConstructorAccessChangingVisibility = true; + } else if (optionValue.equals(VERSION_1_4)) { + this.isPrivateConstructorAccessChangingVisibility = true; + } + continue; + } + // Report method with constructor name + if(optionID.equals(OPTION_ReportMethodWithConstructorName)){ + if (optionValue.equals(ERROR)) { + this.errorThreshold |= MethodWithConstructorName; + this.warningThreshold &= ~MethodWithConstructorName; + } else if (optionValue.equals(WARNING)) { + this.errorThreshold &= ~MethodWithConstructorName; + this.warningThreshold |= MethodWithConstructorName; + } else if (optionValue.equals(IGNORE)) { + this.errorThreshold &= ~MethodWithConstructorName; + this.warningThreshold &= ~MethodWithConstructorName; + } + continue; + } + // Report overriding package default method + if(optionID.equals(OPTION_ReportOverridingPackageDefaultMethod)){ + if (optionValue.equals(ERROR)) { + this.errorThreshold |= OverriddenPackageDefaultMethod; + this.warningThreshold &= ~OverriddenPackageDefaultMethod; + } else if (optionValue.equals(WARNING)) { + this.errorThreshold &= ~OverriddenPackageDefaultMethod; + this.warningThreshold |= OverriddenPackageDefaultMethod; + } else if (optionValue.equals(IGNORE)) { + this.errorThreshold &= ~OverriddenPackageDefaultMethod; + this.warningThreshold &= ~OverriddenPackageDefaultMethod; + } + continue; + } + // Report deprecation + if(optionID.equals(OPTION_ReportDeprecation)){ + if (optionValue.equals(ERROR)) { + this.errorThreshold |= UsingDeprecatedAPI; + this.warningThreshold &= ~UsingDeprecatedAPI; + } else if (optionValue.equals(WARNING)) { + this.errorThreshold &= ~UsingDeprecatedAPI; + this.warningThreshold |= UsingDeprecatedAPI; + } else if (optionValue.equals(IGNORE)) { + this.errorThreshold &= ~UsingDeprecatedAPI; + this.warningThreshold &= ~UsingDeprecatedAPI; + } + continue; + } + // Report hidden catch block + if(optionID.equals(OPTION_ReportHiddenCatchBlock)){ + if (optionValue.equals(ERROR)) { + this.errorThreshold |= MaskedCatchBlock; + this.warningThreshold &= ~MaskedCatchBlock; + } else if (optionValue.equals(WARNING)) { + this.errorThreshold &= ~MaskedCatchBlock; + this.warningThreshold |= MaskedCatchBlock; + } else if (optionValue.equals(IGNORE)) { + this.errorThreshold &= ~MaskedCatchBlock; + this.warningThreshold &= ~MaskedCatchBlock; + } + continue; + } + // Report unused local variable + if(optionID.equals(OPTION_ReportUnusedLocal)){ + if (optionValue.equals(ERROR)) { + this.errorThreshold |= UnusedLocalVariable; + this.warningThreshold &= ~UnusedLocalVariable; + } else if (optionValue.equals(WARNING)) { + this.errorThreshold &= ~UnusedLocalVariable; + this.warningThreshold |= UnusedLocalVariable; + } else if (optionValue.equals(IGNORE)) { + this.errorThreshold &= ~UnusedLocalVariable; + this.warningThreshold &= ~UnusedLocalVariable; + } + continue; + } + // Report unused parameter + if(optionID.equals(OPTION_ReportUnusedParameter)){ + if (optionValue.equals(ERROR)) { + this.errorThreshold |= UnusedArgument; + this.warningThreshold &= ~UnusedArgument; + } else if (optionValue.equals(WARNING)) { + this.errorThreshold &= ~UnusedArgument; + this.warningThreshold |= UnusedArgument; + } else if (optionValue.equals(IGNORE)) { + this.errorThreshold &= ~UnusedArgument; + this.warningThreshold &= ~UnusedArgument; + } + continue; + } + // Report unused parameter + if(optionID.equals(OPTION_ReportUnusedImport)){ + if (optionValue.equals(ERROR)) { + this.errorThreshold |= UnusedImport; + this.warningThreshold &= ~UnusedImport; + } else if (optionValue.equals(WARNING)) { + this.errorThreshold &= ~UnusedImport; + this.warningThreshold |= UnusedImport; + } else if (optionValue.equals(IGNORE)) { + this.errorThreshold &= ~UnusedImport; + this.warningThreshold &= ~UnusedImport; + } + continue; + } + // Report synthetic access emulation + if(optionID.equals(OPTION_ReportSyntheticAccessEmulation)){ + if (optionValue.equals(ERROR)) { + this.errorThreshold |= AccessEmulation; + this.warningThreshold &= ~AccessEmulation; + } else if (optionValue.equals(WARNING)) { + this.errorThreshold &= ~AccessEmulation; + this.warningThreshold |= AccessEmulation; + } else if (optionValue.equals(IGNORE)) { + this.errorThreshold &= ~AccessEmulation; + this.warningThreshold &= ~AccessEmulation; + } + continue; + } + // Report non-externalized string literals + if(optionID.equals(OPTION_ReportNonExternalizedStringLiteral)){ + if (optionValue.equals(ERROR)) { + this.errorThreshold |= NonExternalizedString; + this.warningThreshold &= ~NonExternalizedString; + } else if (optionValue.equals(WARNING)) { + this.errorThreshold &= ~NonExternalizedString; + this.warningThreshold |= NonExternalizedString; + } else if (optionValue.equals(IGNORE)) { + this.errorThreshold &= ~NonExternalizedString; + this.warningThreshold &= ~NonExternalizedString; + } + continue; + } + // Report usage of 'assert' as an identifier + if(optionID.equals(OPTION_ReportAssertIdentifier)){ + if (optionValue.equals(ERROR)) { + this.errorThreshold |= AssertUsedAsAnIdentifier; + this.warningThreshold &= ~AssertUsedAsAnIdentifier; + } else if (optionValue.equals(WARNING)) { + this.errorThreshold &= ~AssertUsedAsAnIdentifier; + this.warningThreshold |= AssertUsedAsAnIdentifier; + } else if (optionValue.equals(IGNORE)) { + this.errorThreshold &= ~AssertUsedAsAnIdentifier; + this.warningThreshold &= ~AssertUsedAsAnIdentifier; + } + continue; + } + // Set the source compatibility mode (assertions) + if(optionID.equals(OPTION_Source)){ + if (optionValue.equals(VERSION_1_3)) { + this.assertMode = false; + } else if (optionValue.equals(VERSION_1_4)) { + this.assertMode = true; + } + continue; + } + // Set the default encoding format + if(optionID.equals(OPTION_Encoding)){ + if (optionValue.length() == 0){ + this.defaultEncoding = null; + } else { + try { // ignore unsupported encoding + new InputStreamReader(new ByteArrayInputStream(new byte[0]), optionValue); + this.defaultEncoding = optionValue; + } catch(UnsupportedEncodingException e){ + } + } + continue; + } + // Set the threshold for problems per unit + if(optionID.equals(OPTION_MaxProblemPerUnit)){ + try { + int val = Integer.parseInt(optionValue); + if (val >= 0) this.maxProblemsPerUnit = val; + } catch(NumberFormatException e){ + } + continue; + } + } + } + + public int getTargetJDK() { + return this.targetJDK; + } + + public int getNonExternalizedStringLiteralSeverity() { + if((warningThreshold & NonExternalizedString) != 0) + return Warning; + if((errorThreshold & NonExternalizedString) != 0) + return Error; + return Ignore; + } + + public void produceReferenceInfo(boolean flag) { + this.produceReferenceInfo = flag; + } + + public void setVerboseMode(boolean flag) { + this.verbose = flag; + } + + public String toString() { + + + StringBuffer buf = new StringBuffer("CompilerOptions:"); //$NON-NLS-1$ + if ((produceDebugAttributes & Vars) != 0){ + buf.append("\n-local variables debug attributes: ON"); //$NON-NLS-1$ + } else { + buf.append("\n-local variables debug attributes: OFF"); //$NON-NLS-1$ + } + if ((produceDebugAttributes & Lines) != 0){ + buf.append("\n-line number debug attributes: ON"); //$NON-NLS-1$ + } else { + buf.append("\n-line number debug attributes: OFF"); //$NON-NLS-1$ + } + if ((produceDebugAttributes & Source) != 0){ + buf.append("\n-source debug attributes: ON"); //$NON-NLS-1$ + } else { + buf.append("\n-source debug attributes: OFF"); //$NON-NLS-1$ + } + if (preserveAllLocalVariables){ + buf.append("\n-preserve all local variables: ON"); //$NON-NLS-1$ + } else { + buf.append("\n-preserve all local variables: OFF"); //$NON-NLS-1$ + } + if ((errorThreshold & UnreachableCode) != 0){ + buf.append("\n-unreachable code: ERROR"); //$NON-NLS-1$ + } else { + if ((warningThreshold & UnreachableCode) != 0){ + buf.append("\n-unreachable code: WARNING"); //$NON-NLS-1$ + } else { + buf.append("\n-unreachable code: IGNORE"); //$NON-NLS-1$ + } + } + if ((errorThreshold & ImportProblem) != 0){ + buf.append("\n-import problem: ERROR"); //$NON-NLS-1$ + } else { + if ((warningThreshold & ImportProblem) != 0){ + buf.append("\n-import problem: WARNING"); //$NON-NLS-1$ + } else { + buf.append("\n-import problem: IGNORE"); //$NON-NLS-1$ + } + } + if ((errorThreshold & MethodWithConstructorName) != 0){ + buf.append("\n-method with constructor name: ERROR"); //$NON-NLS-1$ + } else { + if ((warningThreshold & MethodWithConstructorName) != 0){ + buf.append("\n-method with constructor name: WARNING"); //$NON-NLS-1$ + } else { + buf.append("\n-method with constructor name: IGNORE"); //$NON-NLS-1$ + } + } + if ((errorThreshold & OverriddenPackageDefaultMethod) != 0){ + buf.append("\n-overridden package default method: ERROR"); //$NON-NLS-1$ + } else { + if ((warningThreshold & OverriddenPackageDefaultMethod) != 0){ + buf.append("\n-overridden package default method: WARNING"); //$NON-NLS-1$ + } else { + buf.append("\n-overridden package default method: IGNORE"); //$NON-NLS-1$ + } + } + if ((errorThreshold & UsingDeprecatedAPI) != 0){ + buf.append("\n-deprecation: ERROR"); //$NON-NLS-1$ + } else { + if ((warningThreshold & UsingDeprecatedAPI) != 0){ + buf.append("\n-deprecation: WARNING"); //$NON-NLS-1$ + } else { + buf.append("\n-deprecation: IGNORE"); //$NON-NLS-1$ + } + } + if ((errorThreshold & MaskedCatchBlock) != 0){ + buf.append("\n-masked catch block: ERROR"); //$NON-NLS-1$ + } else { + if ((warningThreshold & MaskedCatchBlock) != 0){ + buf.append("\n-masked catch block: WARNING"); //$NON-NLS-1$ + } else { + buf.append("\n-masked catch block: IGNORE"); //$NON-NLS-1$ + } + } + if ((errorThreshold & UnusedLocalVariable) != 0){ + buf.append("\n-unused local variable: ERROR"); //$NON-NLS-1$ + } else { + if ((warningThreshold & UnusedLocalVariable) != 0){ + buf.append("\n-unused local variable: WARNING"); //$NON-NLS-1$ + } else { + buf.append("\n-unused local variable: IGNORE"); //$NON-NLS-1$ + } + } + if ((errorThreshold & UnusedArgument) != 0){ + buf.append("\n-unused parameter: ERROR"); //$NON-NLS-1$ + } else { + if ((warningThreshold & UnusedArgument) != 0){ + buf.append("\n-unused parameter: WARNING"); //$NON-NLS-1$ + } else { + buf.append("\n-unused parameter: IGNORE"); //$NON-NLS-1$ + } + } + if ((errorThreshold & UnusedImport) != 0){ + buf.append("\n-unused import: ERROR"); //$NON-NLS-1$ + } else { + if ((warningThreshold & UnusedImport) != 0){ + buf.append("\n-unused import: WARNING"); //$NON-NLS-1$ + } else { + buf.append("\n-unused import: IGNORE"); //$NON-NLS-1$ + } + } + if ((errorThreshold & AccessEmulation) != 0){ + buf.append("\n-synthetic access emulation: ERROR"); //$NON-NLS-1$ + } else { + if ((warningThreshold & AccessEmulation) != 0){ + buf.append("\n-synthetic access emulation: WARNING"); //$NON-NLS-1$ + } else { + buf.append("\n-synthetic access emulation: IGNORE"); //$NON-NLS-1$ + } + } + if ((errorThreshold & NonExternalizedString) != 0){ + buf.append("\n-non externalized string: ERROR"); //$NON-NLS-1$ + } else { + if ((warningThreshold & NonExternalizedString) != 0){ + buf.append("\n-non externalized string: WARNING"); //$NON-NLS-1$ + } else { + buf.append("\n-non externalized string: IGNORE"); //$NON-NLS-1$ + } + } + switch(targetJDK){ + case JDK1_1 : + buf.append("\n-target JDK: 1.1"); //$NON-NLS-1$ + break; + case JDK1_2 : + buf.append("\n-target JDK: 1.2"); //$NON-NLS-1$ + break; + case JDK1_3 : + buf.append("\n-target JDK: 1.3"); //$NON-NLS-1$ + break; + case JDK1_4 : + buf.append("\n-target JDK: 1.4"); //$NON-NLS-1$ + break; + } + switch(complianceLevel){ + case JDK1_1 : + buf.append("\n-compliance JDK: 1.1"); //$NON-NLS-1$ + break; + case JDK1_2 : + buf.append("\n-compliance JDK: 1.2"); //$NON-NLS-1$ + break; + case JDK1_3 : + buf.append("\n-compliance JDK: 1.3"); //$NON-NLS-1$ + break; + case JDK1_4 : + buf.append("\n-compliance JDK: 1.4"); //$NON-NLS-1$ + break; + } + if (isPrivateConstructorAccessChangingVisibility){ + buf.append("\n-private constructor access emulation: extra argument"); //$NON-NLS-1$ + } else { + buf.append("\n-private constructor access emulation: make default access"); //$NON-NLS-1$ + } + buf.append("\n-verbose : " + (verbose ? "ON" : "OFF")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + buf.append("\n-produce reference info : " + (produceReferenceInfo ? "ON" : "OFF")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + buf.append("\n-parse literal expressions as constants : " + (parseLiteralExpressionsAsConstants ? "ON" : "OFF")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + buf.append("\n-runtime exception name for compile error : " + runtimeExceptionNameForCompileError); //$NON-NLS-1$ + buf.append("\n-encoding : " + (defaultEncoding == null ? "" : defaultEncoding)); //$NON-NLS-1$ //$NON-NLS-2$ + return buf.toString(); + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/Constant.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/Constant.java new file mode 100644 index 0000000..5a5eaee --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/Constant.java @@ -0,0 +1,1492 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.impl; + +import net.sourceforge.phpdt.internal.compiler.ast.OperatorIds; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeIds; +import net.sourceforge.phpdt.internal.compiler.problem.ShouldNotImplement; +import net.sourceforge.phpdt.internal.compiler.util.Util; + +public abstract class Constant implements TypeIds, OperatorIds { + public static final Constant NotAConstant = new DoubleConstant(Double.NaN); + + public static final IntConstant Zero = new IntConstant(0); + public static final IntConstant Two = new IntConstant(2); + public static final IntConstant One = new IntConstant(1); +public boolean booleanValue() { + throw new ShouldNotImplement(Util.bind("constant.cannotCastedInto",typeName(),"boolean")); //$NON-NLS-1$ //$NON-NLS-2$ +} +public byte byteValue() { + throw new ShouldNotImplement(Util.bind("constant.cannotCastedInto",typeName(),"byte")); //$NON-NLS-1$ //$NON-NLS-2$ +} +public final Constant castTo(int conversionToTargetType){ + //the cast is an int of the form + // (castId<<4)+typeId (in order to follow the + //user written style (cast)expression .... + //This method assumes that the TC is done (correctly :-) + + if (this == NotAConstant) return NotAConstant ; + switch(conversionToTargetType){ + case T_undefined : return this; +// case (T_undefined<<4)+T_undefined : return NotAConstant ; +// case (T_undefined<<4)+T_byte : return NotAConstant ; +// case (T_undefined<<4)+T_long : return NotAConstant ; +// case (T_undefined<<4)+T_short : return NotAConstant ; +// case (T_undefined<<4)+T_void : return NotAConstant ; +// case (T_undefined<<4)+T_String : return NotAConstant ; +// case (T_undefined<<4)+T_Object : return NotAConstant ; +// case (T_undefined<<4)+T_double : return NotAConstant ; +// case (T_undefined<<4)+T_float : return NotAConstant ; +// case (T_undefined<<4)+T_boolean : return NotAConstant ; +// case (T_undefined<<4)+T_char : return NotAConstant ; +// case (T_undefined<<4)+T_int : return NotAConstant ; +// case (T_undefined<<4)+T_null : return NotAConstant ; + +// case (T_byte<<4)+T_undefined : return NotAConstant ; + case (T_byte<<4)+T_byte : return this ; + case (T_byte<<4)+T_long : return Constant.fromValue((byte)this.longValue()) ; + case (T_byte<<4)+T_short : return Constant.fromValue((byte)this.shortValue()); +// case (T_byte<<4)+T_void : return NotAConstant ; +// case (T_byte<<4)+T_String : return NotAConstant ; +// case (T_byte<<4)+T_Object : return NotAConstant ; + case (T_byte<<4)+T_double : return Constant.fromValue((byte)this.doubleValue()); + case (T_byte<<4)+T_float : return Constant.fromValue((byte)this.floatValue()); +// case (T_byte<<4)+T_boolean : return NotAConstant ; + case (T_byte<<4)+T_char : return Constant.fromValue((byte)this.charValue()); + case (T_byte<<4)+T_int : return Constant.fromValue((byte)this.intValue()); +// case (T_byte<<4)+T_null : return NotAConstant ; + +// case (T_long<<4)+T_undefined : return NotAConstant ; + case (T_long<<4)+T_byte : return Constant.fromValue((long)this.byteValue()); + case (T_long<<4)+T_long : return this ; + case (T_long<<4)+T_short : return Constant.fromValue((long)this.shortValue()); +// case (T_long<<4)+T_void : return NotAConstant ; +// case (T_long<<4)+T_String : return NotAConstant ; +// case (T_long<<4)+T_Object : return NotAConstant ; + case (T_long<<4)+T_double : return Constant.fromValue((long)this.doubleValue()); + case (T_long<<4)+T_float : return Constant.fromValue((long)this.floatValue()); +// case (T_long<<4)+T_boolean : return NotAConstant ; + case (T_long<<4)+T_char : return Constant.fromValue((long)this.charValue()); + case (T_long<<4)+T_int : return Constant.fromValue((long)this.intValue()); +// case (T_long<<4)+T_null : return NotAConstant ; + +// case (T_short<<4)+T_undefined : return NotAConstant ; + case (T_short<<4)+T_byte : return Constant.fromValue((short)this.byteValue()); + case (T_short<<4)+T_long : return Constant.fromValue((short)this.longValue()); + case (T_short<<4)+T_short : return this ; +// case (T_short<<4)+T_void : return NotAConstant ; +// case (T_short<<4)+T_String : return NotAConstant ; +// case (T_short<<4)+T_Object : return NotAConstant ; + case (T_short<<4)+T_double : return Constant.fromValue((short)this.doubleValue()) ; + case (T_short<<4)+T_float : return Constant.fromValue((short)this.floatValue()) ; +// case (T_short<<4)+T_boolean : return NotAConstant ; + case (T_short<<4)+T_char : return Constant.fromValue((short)this.charValue()) ; + case (T_short<<4)+T_int : return Constant.fromValue((short)this.intValue()) ; +// case (T_short<<4)+T_null : return NotAConstant ; + +// case (T_void<<4)+T_undefined : return NotAConstant ; +// case (T_void<<4)+T_byte : return NotAConstant ; +// case (T_void<<4)+T_long : return NotAConstant ; +// case (T_void<<4)+T_short : return NotAConstant ; +// case (T_void<<4)+T_void : return NotAConstant ; +// case (T_void<<4)+T_String : return NotAConstant ; +// case (T_void<<4)+T_Object : return NotAConstant ; +// case (T_void<<4)+T_double : return NotAConstant ; +// case (T_void<<4)+T_float : return NotAConstant ; +// case (T_void<<4)+T_boolean : return NotAConstant ; +// case (T_void<<4)+T_char : return NotAConstant ; +// case (T_void<<4)+T_int : return NotAConstant ; +// case (T_void<<4)+T_null : return NotAConstant ; + +// case (T_String<<4)+T_undefined : return NotAConstant ; +// case (T_String<<4)+T_byte : return NotAConstant ; +// case (T_String<<4)+T_long : return NotAConstant ; +// case (T_String<<4)+T_short : return NotAConstant ; +// case (T_String<<4)+T_void : return NotAConstant ; + case (T_String<<4)+T_String : return this ; +// case (T_String<<4)+T_Object : return NotAConstant ; +// case (T_String<<4)+T_double : return NotAConstant ; +// case (T_String<<4)+T_float : return NotAConstant ; +// case (T_String<<4)+T_boolean : return NotAConstant ; +// case (T_String<<4)+T_char : return NotAConstant ; +// case (T_String<<4)+T_int : return NotAConstant ; +// case (T_String<<4)+T_null : return NotAConstant ; + +// case (T_Object<<4)+T_undefined : return NotAConstant ; +// case (T_Object<<4)+T_byte : return NotAConstant ; +// case (T_Object<<4)+T_long : return NotAConstant ; +// case (T_Object<<4)+T_short : return NotAConstant ; +// case (T_Object<<4)+T_void : return NotAConstant ; +// case (T_Object<<4)+T_String : return NotAConstant ; +// case (T_Object<<4)+T_Object : return NotAConstant ; +// case (T_Object<<4)+T_double : return NotAConstant ; +// case (T_Object<<4)+T_float : return NotAConstant ; +// case (T_Object<<4)+T_boolean : return NotAConstant ; +// case (T_Object<<4)+T_char : return NotAConstant ; +// case (T_Object<<4)+T_int : return NotAConstant ; + case (T_Object<<4)+T_null : return this ; + +// case (T_double<<4)+T_undefined : return NotAConstant ; + case (T_double<<4)+T_byte : return Constant.fromValue((double)this.byteValue()) ; + case (T_double<<4)+T_long : return Constant.fromValue((double)this.longValue()) ; + case (T_double<<4)+T_short : return Constant.fromValue((double)this.shortValue()) ; +// case (T_double<<4)+T_void : return NotAConstant ; +// case (T_double<<4)+T_String : return NotAConstant ; +// case (T_double<<4)+T_Object : return NotAConstant ; + case (T_double<<4)+T_double : return this ; + case (T_double<<4)+T_float : return Constant.fromValue((double)this.floatValue()) ; +// case (T_double<<4)+T_boolean : return NotAConstant ; + case (T_double<<4)+T_char : return Constant.fromValue((double)this.charValue()) ; + case (T_double<<4)+T_int : return Constant.fromValue((double)this.intValue()); +// case (T_double<<4)+T_null : return NotAConstant ; + +// case (T_float<<4)+T_undefined : return NotAConstant ; + case (T_float<<4)+T_byte : return Constant.fromValue((float)this.byteValue()) ; + case (T_float<<4)+T_long : return Constant.fromValue((float)this.longValue()) ; + case (T_float<<4)+T_short : return Constant.fromValue((float)this.shortValue()) ; +// case (T_float<<4)+T_void : return NotAConstant ; +// case (T_float<<4)+T_String : return NotAConstant ; +// case (T_float<<4)+T_Object : return NotAConstant ; + case (T_float<<4)+T_double : return Constant.fromValue((float)this.doubleValue()) ; + case (T_float<<4)+T_float : return this ; +// case (T_float<<4)+T_boolean : return NotAConstant ; + case (T_float<<4)+T_char : return Constant.fromValue((float)this.charValue()) ; + case (T_float<<4)+T_int : return Constant.fromValue((float)this.intValue()) ; +// case (T_float<<4)+T_null : return NotAConstant ; + +// case (T_boolean<<4)+T_undefined : return NotAConstant ; +// case (T_boolean<<4)+T_byte : return NotAConstant ; +// case (T_boolean<<4)+T_long : return NotAConstant ; +// case (T_boolean<<4)+T_short : return NotAConstant ; +// case (T_boolean<<4)+T_void : return NotAConstant ; +// case (T_boolean<<4)+T_String : return NotAConstant ; +// case (T_boolean<<4)+T_Object : return NotAConstant ; +// case (T_boolean<<4)+T_double : return NotAConstant ; +// case (T_boolean<<4)+T_float : return NotAConstant ; + case (T_boolean<<4)+T_boolean : return this ; +// case (T_boolean<<4)+T_char : return NotAConstant ; +// case (T_boolean<<4)+T_int : return NotAConstant ; +// case (T_boolean<<4)+T_null : return NotAConstant ; + +// case (T_char<<4)+T_undefined : return NotAConstant ; + case (T_char<<4)+T_byte : return Constant.fromValue((char)this.byteValue()) ; + case (T_char<<4)+T_long : return Constant.fromValue((char)this.longValue()) ; + case (T_char<<4)+T_short : return Constant.fromValue((char)this.shortValue()) ; +// case (T_char<<4)+T_void : return NotAConstant ; +// case (T_char<<4)+T_String : return NotAConstant ; +// case (T_char<<4)+T_Object : return NotAConstant ; + case (T_char<<4)+T_double : return Constant.fromValue((char)this.doubleValue()) ; + case (T_char<<4)+T_float : return Constant.fromValue((char)this.floatValue()) ; +// case (T_char<<4)+T_boolean : return NotAConstant ; + case (T_char<<4)+T_char : return this ; + case (T_char<<4)+T_int : return Constant.fromValue((char)this.intValue()) ; +// case (T_char<<4)+T_null : return NotAConstant ; + +// case (T_int<<4)+T_undefined : return NotAConstant ; + case (T_int<<4)+T_byte : return Constant.fromValue((int)this.byteValue()) ; + case (T_int<<4)+T_long : return Constant.fromValue((int)this.longValue()) ; + case (T_int<<4)+T_short : return Constant.fromValue((int)this.shortValue()) ; +// case (T_int<<4)+T_void : return NotAConstant ; +// case (T_int<<4)+T_String : return NotAConstant ; +// case (T_int<<4)+T_Object : return NotAConstant ; + case (T_int<<4)+T_double : return Constant.fromValue((int)this.doubleValue()) ; + case (T_int<<4)+T_float : return Constant.fromValue((int)this.floatValue()) ; +// case (T_int<<4)+T_boolean : return NotAConstant ; + case (T_int<<4)+T_char : return Constant.fromValue((int)this.charValue()) ; + case (T_int<<4)+T_int : return this ; +// case (T_int<<4)+T_null : return NotAConstant ; + +// case (T_null<<4)+T_undefined : return NotAConstant ; +// case (T_null<<4)+T_byte : return NotAConstant ; +// case (T_null<<4)+T_long : return NotAConstant ; +// case (T_null<<4)+T_short : return NotAConstant ; +// case (T_null<<4)+T_void : return NotAConstant ; +// case (T_null<<4)+T_String : return NotAConstant ; +// case (T_null<<4)+T_Object : return NotAConstant ; +// case (T_null<<4)+T_double : return NotAConstant ; +// case (T_null<<4)+T_float : return NotAConstant ; +// case (T_null<<4)+T_boolean : return NotAConstant ; +// case (T_null<<4)+T_char : return NotAConstant ; +// case (T_null<<4)+T_int : return NotAConstant ; + case (T_null<<4)+T_null : return this ; + } + + + + return NotAConstant ; +} +public char charValue() { + throw new ShouldNotImplement(Util.bind("constant.cannotCastedInto",typeName(),"char")); //$NON-NLS-1$ //$NON-NLS-2$ +} +public static final Constant computeConstantOperation(Constant cst, int id, int operator) { + //this method assumes that the TC has been done . + //the result should be availbale with not runtime error + + switch (operator) { + case NOT : + return Constant.fromValue(!cst.booleanValue()); + case PLUS : return cst ; + case MINUS : //the two special -9223372036854775808L and -2147483648 are inlined at parseTime + switch (id){ + case T_float : float f ; + if ( (f= cst.floatValue()) == 0.0f) + { //positive and negative 0.... + if (Float.floatToIntBits(f) == 0) + return Constant.fromValue(-0.0f); + else + return Constant.fromValue(0.0f);} + break; //default case + case T_double : double d ; + if ( (d= cst.doubleValue()) == 0.0d) + { //positive and negative 0.... + if (Double.doubleToLongBits(d) == 0) + return Constant.fromValue(-0.0d); + else + return Constant.fromValue(0.0d);} + break; //default case + } + return computeConstantOperationMINUS(Zero,T_int,operator,cst,id); + case TWIDDLE: + switch (id){ + case T_char : return Constant.fromValue(~ cst.charValue()) ; + case T_byte: return Constant.fromValue(~ cst.byteValue()) ; + case T_short: return Constant.fromValue(~ cst.shortValue()) ; + case T_int: return Constant.fromValue(~ cst.intValue()) ; + case T_long: return Constant.fromValue(~ cst.longValue()) ; + default : return NotAConstant;} //should not occur.....(conservative code) + default : return NotAConstant ;}} //should not occur....(conservative code) +public static final Constant computeConstantOperation(Constant left, int leftId, int operator, Constant right, int rightId) { + //this method assumes that the TC has been done . So (except for divide by zero) + //the result should be availbale with not runtime error + + switch (operator) { + case AND : return computeConstantOperationAND (left,leftId,operator,right,rightId) ; + case AND_AND : return computeConstantOperationAND_AND (left,leftId,operator,right,rightId) ; + case DIVIDE : return computeConstantOperationDIVIDE (left,leftId,operator,right,rightId) ; + case GREATER : return computeConstantOperationGREATER (left,leftId,operator,right,rightId) ; + case GREATER_EQUAL : return computeConstantOperationGREATER_EQUAL(left,leftId,operator,right,rightId) ; + case LEFT_SHIFT : return computeConstantOperationLEFT_SHIFT (left,leftId,operator,right,rightId) ; + case LESS : return computeConstantOperationLESS (left,leftId,operator,right,rightId) ; + case LESS_EQUAL : return computeConstantOperationLESS_EQUAL (left,leftId,operator,right,rightId) ; + case MINUS : return computeConstantOperationMINUS (left,leftId,operator,right,rightId) ; + case MULTIPLY : return computeConstantOperationMULTIPLY (left,leftId,operator,right,rightId) ; + case OR : return computeConstantOperationOR (left,leftId,operator,right,rightId) ; + case OR_OR : return computeConstantOperationOR_OR (left,leftId,operator,right,rightId) ; + case PLUS : return computeConstantOperationPLUS (left,leftId,operator,right,rightId) ; + case REMAINDER : return computeConstantOperationREMAINDER (left,leftId,operator,right,rightId) ; + case RIGHT_SHIFT: return computeConstantOperationRIGHT_SHIFT(left,leftId,operator,right,rightId) ; + case UNSIGNED_RIGHT_SHIFT: return computeConstantOperationUNSIGNED_RIGHT_SHIFT(left,leftId,operator,right,rightId) ; + case XOR : return computeConstantOperationXOR (left,leftId,operator,right,rightId) ; + + default : return NotAConstant ;}} //should not occurs....(conservative code) +public static final Constant computeConstantOperationAND(Constant left, int leftId, int operator, Constant right, int rightId) { + //this method assumes that the TC has been done . + + switch (leftId){ + case T_boolean : return Constant.fromValue(left.booleanValue() & right.booleanValue()) ; + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() & right.charValue()) ; + case T_byte: return Constant.fromValue(left.charValue() & right.byteValue()) ; + case T_short: return Constant.fromValue(left.charValue() & right.shortValue()) ; + case T_int: return Constant.fromValue(left.charValue() & right.intValue()) ; + case T_long: return Constant.fromValue(left.charValue() & right.longValue()) ;} + break ; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() & right.charValue()) ; + case T_byte: return Constant.fromValue(left.byteValue() & right.byteValue()) ; + case T_short: return Constant.fromValue(left.byteValue() & right.shortValue()) ; + case T_int: return Constant.fromValue(left.byteValue() & right.intValue()) ; + case T_long: return Constant.fromValue(left.byteValue() & right.longValue()) ;} + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() & right.charValue()) ; + case T_byte: return Constant.fromValue(left.shortValue() & right.byteValue()) ; + case T_short: return Constant.fromValue(left.shortValue() & right.shortValue()) ; + case T_int: return Constant.fromValue(left.shortValue() & right.intValue()) ; + case T_long: return Constant.fromValue(left.shortValue() & right.longValue()) ;} + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() & right.charValue()) ; + case T_byte: return Constant.fromValue(left.intValue() & right.byteValue()) ; + case T_short: return Constant.fromValue(left.intValue() & right.shortValue()) ; + case T_int: return Constant.fromValue(left.intValue() & right.intValue()) ; + case T_long: return Constant.fromValue(left.intValue() & right.longValue()) ;} + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() & right.charValue()) ; + case T_byte: return Constant.fromValue(left.longValue() & right.byteValue()) ; + case T_short: return Constant.fromValue(left.longValue() & right.shortValue()) ; + case T_int: return Constant.fromValue(left.longValue() & right.intValue()) ; + case T_long: return Constant.fromValue(left.longValue() & right.longValue()) ;} + + } + + + return NotAConstant ;} // should not get here +public static final Constant computeConstantOperationAND_AND(Constant left, int leftId, int operator, Constant right, int rightId) { + //this method assumes that the TC has been done . + + return Constant.fromValue(left.booleanValue() && right.booleanValue()) ;} +public static final Constant computeConstantOperationDIVIDE(Constant left, int leftId, int operator, Constant right, int rightId) { + //this method assumes that the TC has been done . + // the /0 must be handled outside this method (error reporting) + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() / right.charValue()) ; + case T_float: return Constant.fromValue(left.charValue() / right.floatValue()) ; + case T_double: return Constant.fromValue(left.charValue() / right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.charValue() / right.byteValue()) ; + case T_short: return Constant.fromValue(left.charValue() / right.shortValue()) ; + case T_int: return Constant.fromValue(left.charValue() / right.intValue()) ; + case T_long: return Constant.fromValue(left.charValue() / right.longValue()) ;} + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() / right.charValue()) ; + case T_float: return Constant.fromValue(left.floatValue() / right.floatValue()) ; + case T_double: return Constant.fromValue(left.floatValue() / right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.floatValue() / right.byteValue()) ; + case T_short: return Constant.fromValue(left.floatValue() / right.shortValue()) ; + case T_int: return Constant.fromValue(left.floatValue() / right.intValue()) ; + case T_long: return Constant.fromValue(left.floatValue() / right.longValue()) ;} + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() / right.charValue()) ; + case T_float: return Constant.fromValue(left.doubleValue() / right.floatValue()) ; + case T_double: return Constant.fromValue(left.doubleValue() / right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.doubleValue() / right.byteValue()) ; + case T_short: return Constant.fromValue(left.doubleValue() / right.shortValue()) ; + case T_int: return Constant.fromValue(left.doubleValue() / right.intValue()) ; + case T_long: return Constant.fromValue(left.doubleValue() / right.longValue()) ;} + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() / right.charValue()) ; + case T_float: return Constant.fromValue(left.byteValue() / right.floatValue()) ; + case T_double: return Constant.fromValue(left.byteValue() / right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.byteValue() / right.byteValue()) ; + case T_short: return Constant.fromValue(left.byteValue() / right.shortValue()) ; + case T_int: return Constant.fromValue(left.byteValue() / right.intValue()) ; + case T_long: return Constant.fromValue(left.byteValue() / right.longValue()) ;} + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() / right.charValue()) ; + case T_float: return Constant.fromValue(left.shortValue() / right.floatValue()) ; + case T_double: return Constant.fromValue(left.shortValue() / right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.shortValue() / right.byteValue()) ; + case T_short: return Constant.fromValue(left.shortValue() / right.shortValue()) ; + case T_int: return Constant.fromValue(left.shortValue() / right.intValue()) ; + case T_long: return Constant.fromValue(left.shortValue() / right.longValue()) ;} + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() / right.charValue()) ; + case T_float: return Constant.fromValue(left.intValue() / right.floatValue()) ; + case T_double: return Constant.fromValue(left.intValue() / right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.intValue() / right.byteValue()) ; + case T_short: return Constant.fromValue(left.intValue() / right.shortValue()) ; + case T_int: return Constant.fromValue(left.intValue() / right.intValue()) ; + case T_long: return Constant.fromValue(left.intValue() / right.longValue()) ;} + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() / right.charValue()) ; + case T_float: return Constant.fromValue(left.longValue() / right.floatValue()) ; + case T_double: return Constant.fromValue(left.longValue() / right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.longValue() / right.byteValue()) ; + case T_short: return Constant.fromValue(left.longValue() / right.shortValue()) ; + case T_int: return Constant.fromValue(left.longValue() / right.intValue()) ; + case T_long: return Constant.fromValue(left.longValue() / right.longValue()) ;} + + } + + + return NotAConstant ;} //should not get here +public static final Constant computeConstantOperationEQUAL_EQUAL(Constant left, int leftId, int operator, Constant right, int rightId) { + //this method assumes that the TC has been done . + + switch (leftId){ + case T_boolean : + if (rightId == T_boolean) { + return Constant.fromValue(left.booleanValue() == right.booleanValue()) ; + } + break ; + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() == right.charValue()) ; + case T_float: return Constant.fromValue(left.charValue() == right.floatValue()) ; + case T_double: return Constant.fromValue(left.charValue() == right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.charValue() == right.byteValue()) ; + case T_short: return Constant.fromValue(left.charValue() == right.shortValue()) ; + case T_int: return Constant.fromValue(left.charValue() == right.intValue()) ; + case T_long: return Constant.fromValue(left.charValue() == right.longValue()) ;} + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() == right.charValue()) ; + case T_float: return Constant.fromValue(left.floatValue() == right.floatValue()) ; + case T_double: return Constant.fromValue(left.floatValue() == right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.floatValue() == right.byteValue()) ; + case T_short: return Constant.fromValue(left.floatValue() == right.shortValue()) ; + case T_int: return Constant.fromValue(left.floatValue() == right.intValue()) ; + case T_long: return Constant.fromValue(left.floatValue() == right.longValue()) ;} + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() == right.charValue()) ; + case T_float: return Constant.fromValue(left.doubleValue() == right.floatValue()) ; + case T_double: return Constant.fromValue(left.doubleValue() == right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.doubleValue() == right.byteValue()) ; + case T_short: return Constant.fromValue(left.doubleValue() == right.shortValue()) ; + case T_int: return Constant.fromValue(left.doubleValue() == right.intValue()) ; + case T_long: return Constant.fromValue(left.doubleValue() == right.longValue()) ;} + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() == right.charValue()) ; + case T_float: return Constant.fromValue(left.byteValue() == right.floatValue()) ; + case T_double: return Constant.fromValue(left.byteValue() == right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.byteValue() == right.byteValue()) ; + case T_short: return Constant.fromValue(left.byteValue() == right.shortValue()) ; + case T_int: return Constant.fromValue(left.byteValue() == right.intValue()) ; + case T_long: return Constant.fromValue(left.byteValue() == right.longValue()) ;} + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() == right.charValue()) ; + case T_float: return Constant.fromValue(left.shortValue() == right.floatValue()) ; + case T_double: return Constant.fromValue(left.shortValue() == right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.shortValue() == right.byteValue()) ; + case T_short: return Constant.fromValue(left.shortValue() == right.shortValue()) ; + case T_int: return Constant.fromValue(left.shortValue() == right.intValue()) ; + case T_long: return Constant.fromValue(left.shortValue() == right.longValue()) ;} + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() == right.charValue()) ; + case T_float: return Constant.fromValue(left.intValue() == right.floatValue()) ; + case T_double: return Constant.fromValue(left.intValue() == right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.intValue() == right.byteValue()) ; + case T_short: return Constant.fromValue(left.intValue() == right.shortValue()) ; + case T_int: return Constant.fromValue(left.intValue() == right.intValue()) ; + case T_long: return Constant.fromValue(left.intValue() == right.longValue()) ;} + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() == right.charValue()) ; + case T_float: return Constant.fromValue(left.longValue() == right.floatValue()) ; + case T_double: return Constant.fromValue(left.longValue() == right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.longValue() == right.byteValue()) ; + case T_short: return Constant.fromValue(left.longValue() == right.shortValue()) ; + case T_int: return Constant.fromValue(left.longValue() == right.intValue()) ; + case T_long: return Constant.fromValue(left.longValue() == right.longValue()) ;} + break; + case T_String : + if (rightId == T_String) { + //String are intermed in th compiler==>thus if two string constant + //get to be compared, it is an equal on the vale which is done + return Constant.fromValue(((StringConstant)left).compileTimeEqual((StringConstant)right)) ; + } + break; + case T_null : + if (rightId == T_String) { + return Constant.fromValue(false); + } else { + if (rightId == T_null) { + return Constant.fromValue(true) ; + } + } + } + + return Constant.fromValue(false) ;} +public static final Constant computeConstantOperationGREATER(Constant left, int leftId, int operator, Constant right, int rightId) { + //this method assumes that the TC has been done . + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() > right.charValue()) ; + case T_float: return Constant.fromValue(left.charValue() > right.floatValue()) ; + case T_double: return Constant.fromValue(left.charValue() > right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.charValue() > right.byteValue()) ; + case T_short: return Constant.fromValue(left.charValue() > right.shortValue()) ; + case T_int: return Constant.fromValue(left.charValue() > right.intValue()) ; + case T_long: return Constant.fromValue(left.charValue() > right.longValue()) ;} + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() > right.charValue()) ; + case T_float: return Constant.fromValue(left.floatValue() > right.floatValue()) ; + case T_double: return Constant.fromValue(left.floatValue() > right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.floatValue() > right.byteValue()) ; + case T_short: return Constant.fromValue(left.floatValue() > right.shortValue()) ; + case T_int: return Constant.fromValue(left.floatValue() > right.intValue()) ; + case T_long: return Constant.fromValue(left.floatValue() > right.longValue()) ;} + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() > right.charValue()) ; + case T_float: return Constant.fromValue(left.doubleValue() > right.floatValue()) ; + case T_double: return Constant.fromValue(left.doubleValue() > right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.doubleValue() > right.byteValue()) ; + case T_short: return Constant.fromValue(left.doubleValue() > right.shortValue()) ; + case T_int: return Constant.fromValue(left.doubleValue() > right.intValue()) ; + case T_long: return Constant.fromValue(left.doubleValue() > right.longValue()) ;} + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() > right.charValue()) ; + case T_float: return Constant.fromValue(left.byteValue() > right.floatValue()) ; + case T_double: return Constant.fromValue(left.byteValue() > right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.byteValue() > right.byteValue()) ; + case T_short: return Constant.fromValue(left.byteValue() > right.shortValue()) ; + case T_int: return Constant.fromValue(left.byteValue() > right.intValue()) ; + case T_long: return Constant.fromValue(left.byteValue() > right.longValue()) ;} + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() > right.charValue()) ; + case T_float: return Constant.fromValue(left.shortValue() > right.floatValue()) ; + case T_double: return Constant.fromValue(left.shortValue() > right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.shortValue() > right.byteValue()) ; + case T_short: return Constant.fromValue(left.shortValue() > right.shortValue()) ; + case T_int: return Constant.fromValue(left.shortValue() > right.intValue()) ; + case T_long: return Constant.fromValue(left.shortValue() > right.longValue()) ;} + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() > right.charValue()) ; + case T_float: return Constant.fromValue(left.intValue() > right.floatValue()) ; + case T_double: return Constant.fromValue(left.intValue() > right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.intValue() > right.byteValue()) ; + case T_short: return Constant.fromValue(left.intValue() > right.shortValue()) ; + case T_int: return Constant.fromValue(left.intValue() > right.intValue()) ; + case T_long: return Constant.fromValue(left.intValue() > right.longValue()) ;} + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() > right.charValue()) ; + case T_float: return Constant.fromValue(left.longValue() > right.floatValue()) ; + case T_double: return Constant.fromValue(left.longValue() > right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.longValue() > right.byteValue()) ; + case T_short: return Constant.fromValue(left.longValue() > right.shortValue()) ; + case T_int: return Constant.fromValue(left.longValue() > right.intValue()) ; + case T_long: return Constant.fromValue(left.longValue() > right.longValue()) ;} + + } + + return NotAConstant ;} //should not get here +public static final Constant computeConstantOperationGREATER_EQUAL(Constant left, int leftId, int operator, Constant right, int rightId) { + //this method assumes that the TC has been done . + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() >= right.charValue()) ; + case T_float: return Constant.fromValue(left.charValue() >= right.floatValue()) ; + case T_double: return Constant.fromValue(left.charValue() >= right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.charValue() >= right.byteValue()) ; + case T_short: return Constant.fromValue(left.charValue() >= right.shortValue()) ; + case T_int: return Constant.fromValue(left.charValue() >= right.intValue()) ; + case T_long: return Constant.fromValue(left.charValue() >= right.longValue()) ;} + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() >= right.charValue()) ; + case T_float: return Constant.fromValue(left.floatValue() >= right.floatValue()) ; + case T_double: return Constant.fromValue(left.floatValue() >= right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.floatValue() >= right.byteValue()) ; + case T_short: return Constant.fromValue(left.floatValue() >= right.shortValue()) ; + case T_int: return Constant.fromValue(left.floatValue() >= right.intValue()) ; + case T_long: return Constant.fromValue(left.floatValue() >= right.longValue()) ;} + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() >= right.charValue()) ; + case T_float: return Constant.fromValue(left.doubleValue() >= right.floatValue()) ; + case T_double: return Constant.fromValue(left.doubleValue() >= right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.doubleValue() >= right.byteValue()) ; + case T_short: return Constant.fromValue(left.doubleValue() >= right.shortValue()) ; + case T_int: return Constant.fromValue(left.doubleValue() >= right.intValue()) ; + case T_long: return Constant.fromValue(left.doubleValue() >= right.longValue()) ;} + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() >= right.charValue()) ; + case T_float: return Constant.fromValue(left.byteValue() >= right.floatValue()) ; + case T_double: return Constant.fromValue(left.byteValue() >= right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.byteValue() >= right.byteValue()) ; + case T_short: return Constant.fromValue(left.byteValue() >= right.shortValue()) ; + case T_int: return Constant.fromValue(left.byteValue() >= right.intValue()) ; + case T_long: return Constant.fromValue(left.byteValue() >= right.longValue()) ;} + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() >= right.charValue()) ; + case T_float: return Constant.fromValue(left.shortValue() >= right.floatValue()) ; + case T_double: return Constant.fromValue(left.shortValue() >= right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.shortValue() >= right.byteValue()) ; + case T_short: return Constant.fromValue(left.shortValue() >= right.shortValue()) ; + case T_int: return Constant.fromValue(left.shortValue() >= right.intValue()) ; + case T_long: return Constant.fromValue(left.shortValue() >= right.longValue()) ;} + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() >= right.charValue()) ; + case T_float: return Constant.fromValue(left.intValue() >= right.floatValue()) ; + case T_double: return Constant.fromValue(left.intValue() >= right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.intValue() >= right.byteValue()) ; + case T_short: return Constant.fromValue(left.intValue() >= right.shortValue()) ; + case T_int: return Constant.fromValue(left.intValue() >= right.intValue()) ; + case T_long: return Constant.fromValue(left.intValue() >= right.longValue()) ;} + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() >= right.charValue()) ; + case T_float: return Constant.fromValue(left.longValue() >= right.floatValue()) ; + case T_double: return Constant.fromValue(left.longValue() >= right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.longValue() >= right.byteValue()) ; + case T_short: return Constant.fromValue(left.longValue() >= right.shortValue()) ; + case T_int: return Constant.fromValue(left.longValue() >= right.intValue()) ; + case T_long: return Constant.fromValue(left.longValue() >= right.longValue()) ;} + + } + + return NotAConstant ;} //should not get here +public static final Constant computeConstantOperationLEFT_SHIFT(Constant left, int leftId, int operator, Constant right, int rightId) { + //this method assumes that the TC has been done . + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() << right.charValue()) ; + case T_byte: return Constant.fromValue(left.charValue() << right.byteValue()) ; + case T_short: return Constant.fromValue(left.charValue() << right.shortValue()) ; + case T_int: return Constant.fromValue(left.charValue() << right.intValue()) ; + case T_long: return Constant.fromValue(left.charValue() << right.longValue()) ;} + break ; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() << right.charValue()) ; + case T_byte: return Constant.fromValue(left.byteValue() << right.byteValue()) ; + case T_short: return Constant.fromValue(left.byteValue() << right.shortValue()) ; + case T_int: return Constant.fromValue(left.byteValue() << right.intValue()) ; + case T_long: return Constant.fromValue(left.byteValue() << right.longValue()) ;} + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() << right.charValue()) ; + case T_byte: return Constant.fromValue(left.shortValue() << right.byteValue()) ; + case T_short: return Constant.fromValue(left.shortValue() << right.shortValue()) ; + case T_int: return Constant.fromValue(left.shortValue() << right.intValue()) ; + case T_long: return Constant.fromValue(left.shortValue() << right.longValue()) ;} + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() << right.charValue()) ; + case T_byte: return Constant.fromValue(left.intValue() << right.byteValue()) ; + case T_short: return Constant.fromValue(left.intValue() << right.shortValue()) ; + case T_int: return Constant.fromValue(left.intValue() << right.intValue()) ; + case T_long: return Constant.fromValue(left.intValue() << right.longValue()) ;} + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() << right.charValue()) ; + case T_byte: return Constant.fromValue(left.longValue() << right.byteValue()) ; + case T_short: return Constant.fromValue(left.longValue() << right.shortValue()) ; + case T_int: return Constant.fromValue(left.longValue() << right.intValue()) ; + case T_long: return Constant.fromValue(left.longValue() << right.longValue()) ;} + + } + + + return NotAConstant ;} // should not get here +public static final Constant computeConstantOperationLESS(Constant left, int leftId, int operator, Constant right, int rightId) { + //this method assumes that the TC has been done . + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() < right.charValue()) ; + case T_float: return Constant.fromValue(left.charValue() < right.floatValue()) ; + case T_double: return Constant.fromValue(left.charValue() < right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.charValue() < right.byteValue()) ; + case T_short: return Constant.fromValue(left.charValue() < right.shortValue()) ; + case T_int: return Constant.fromValue(left.charValue() < right.intValue()) ; + case T_long: return Constant.fromValue(left.charValue() < right.longValue()) ;} + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() < right.charValue()) ; + case T_float: return Constant.fromValue(left.floatValue() < right.floatValue()) ; + case T_double: return Constant.fromValue(left.floatValue() < right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.floatValue() < right.byteValue()) ; + case T_short: return Constant.fromValue(left.floatValue() < right.shortValue()) ; + case T_int: return Constant.fromValue(left.floatValue() < right.intValue()) ; + case T_long: return Constant.fromValue(left.floatValue() < right.longValue()) ;} + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() < right.charValue()) ; + case T_float: return Constant.fromValue(left.doubleValue() < right.floatValue()) ; + case T_double: return Constant.fromValue(left.doubleValue() < right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.doubleValue() < right.byteValue()) ; + case T_short: return Constant.fromValue(left.doubleValue() < right.shortValue()) ; + case T_int: return Constant.fromValue(left.doubleValue() < right.intValue()) ; + case T_long: return Constant.fromValue(left.doubleValue() < right.longValue()) ;} + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() < right.charValue()) ; + case T_float: return Constant.fromValue(left.byteValue() < right.floatValue()) ; + case T_double: return Constant.fromValue(left.byteValue() < right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.byteValue() < right.byteValue()) ; + case T_short: return Constant.fromValue(left.byteValue() < right.shortValue()) ; + case T_int: return Constant.fromValue(left.byteValue() < right.intValue()) ; + case T_long: return Constant.fromValue(left.byteValue() < right.longValue()) ;} + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() < right.charValue()) ; + case T_float: return Constant.fromValue(left.shortValue() < right.floatValue()) ; + case T_double: return Constant.fromValue(left.shortValue() < right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.shortValue() < right.byteValue()) ; + case T_short: return Constant.fromValue(left.shortValue() < right.shortValue()) ; + case T_int: return Constant.fromValue(left.shortValue() < right.intValue()) ; + case T_long: return Constant.fromValue(left.shortValue() < right.longValue()) ;} + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() < right.charValue()) ; + case T_float: return Constant.fromValue(left.intValue() < right.floatValue()) ; + case T_double: return Constant.fromValue(left.intValue() < right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.intValue() < right.byteValue()) ; + case T_short: return Constant.fromValue(left.intValue() < right.shortValue()) ; + case T_int: return Constant.fromValue(left.intValue() < right.intValue()) ; + case T_long: return Constant.fromValue(left.intValue() < right.longValue()) ;} + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() < right.charValue()) ; + case T_float: return Constant.fromValue(left.longValue() < right.floatValue()) ; + case T_double: return Constant.fromValue(left.longValue() < right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.longValue() < right.byteValue()) ; + case T_short: return Constant.fromValue(left.longValue() < right.shortValue()) ; + case T_int: return Constant.fromValue(left.longValue() < right.intValue()) ; + case T_long: return Constant.fromValue(left.longValue() < right.longValue()) ;} + + } + + return NotAConstant ;} //should not get here +public static final Constant computeConstantOperationLESS_EQUAL(Constant left, int leftId, int operator, Constant right, int rightId) { + //this method assumes that the TC has been done . + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() <= right.charValue()) ; + case T_float: return Constant.fromValue(left.charValue() <= right.floatValue()) ; + case T_double: return Constant.fromValue(left.charValue() <= right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.charValue() <= right.byteValue()) ; + case T_short: return Constant.fromValue(left.charValue() <= right.shortValue()) ; + case T_int: return Constant.fromValue(left.charValue() <= right.intValue()) ; + case T_long: return Constant.fromValue(left.charValue() <= right.longValue()) ;} + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() <= right.charValue()) ; + case T_float: return Constant.fromValue(left.floatValue() <= right.floatValue()) ; + case T_double: return Constant.fromValue(left.floatValue() <= right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.floatValue() <= right.byteValue()) ; + case T_short: return Constant.fromValue(left.floatValue() <= right.shortValue()) ; + case T_int: return Constant.fromValue(left.floatValue() <= right.intValue()) ; + case T_long: return Constant.fromValue(left.floatValue() <= right.longValue()) ;} + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() <= right.charValue()) ; + case T_float: return Constant.fromValue(left.doubleValue() <= right.floatValue()) ; + case T_double: return Constant.fromValue(left.doubleValue() <= right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.doubleValue() <= right.byteValue()) ; + case T_short: return Constant.fromValue(left.doubleValue() <= right.shortValue()) ; + case T_int: return Constant.fromValue(left.doubleValue() <= right.intValue()) ; + case T_long: return Constant.fromValue(left.doubleValue() <= right.longValue()) ;} + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() <= right.charValue()) ; + case T_float: return Constant.fromValue(left.byteValue() <= right.floatValue()) ; + case T_double: return Constant.fromValue(left.byteValue() <= right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.byteValue() <= right.byteValue()) ; + case T_short: return Constant.fromValue(left.byteValue() <= right.shortValue()) ; + case T_int: return Constant.fromValue(left.byteValue() <= right.intValue()) ; + case T_long: return Constant.fromValue(left.byteValue() <= right.longValue()) ;} + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() <= right.charValue()) ; + case T_float: return Constant.fromValue(left.shortValue() <= right.floatValue()) ; + case T_double: return Constant.fromValue(left.shortValue() <= right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.shortValue() <= right.byteValue()) ; + case T_short: return Constant.fromValue(left.shortValue() <= right.shortValue()) ; + case T_int: return Constant.fromValue(left.shortValue() <= right.intValue()) ; + case T_long: return Constant.fromValue(left.shortValue() <= right.longValue()) ;} + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() <= right.charValue()) ; + case T_float: return Constant.fromValue(left.intValue() <= right.floatValue()) ; + case T_double: return Constant.fromValue(left.intValue() <= right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.intValue() <= right.byteValue()) ; + case T_short: return Constant.fromValue(left.intValue() <= right.shortValue()) ; + case T_int: return Constant.fromValue(left.intValue() <= right.intValue()) ; + case T_long: return Constant.fromValue(left.intValue() <= right.longValue()) ;} + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() <= right.charValue()) ; + case T_float: return Constant.fromValue(left.longValue() <= right.floatValue()) ; + case T_double: return Constant.fromValue(left.longValue() <= right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.longValue() <= right.byteValue()) ; + case T_short: return Constant.fromValue(left.longValue() <= right.shortValue()) ; + case T_int: return Constant.fromValue(left.longValue() <= right.intValue()) ; + case T_long: return Constant.fromValue(left.longValue() <= right.longValue()) ;} + + } + + return NotAConstant ;} //should not get here +public static final Constant computeConstantOperationMINUS(Constant left, int leftId, int operator, Constant right, int rightId) { + //this method assumes that the TC has been done . + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() - right.charValue()) ; + case T_float: return Constant.fromValue(left.charValue() - right.floatValue()) ; + case T_double: return Constant.fromValue(left.charValue() - right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.charValue() - right.byteValue()) ; + case T_short: return Constant.fromValue(left.charValue() - right.shortValue()) ; + case T_int: return Constant.fromValue(left.charValue() - right.intValue()) ; + case T_long: return Constant.fromValue(left.charValue() - right.longValue()) ;} + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() - right.charValue()) ; + case T_float: return Constant.fromValue(left.floatValue() - right.floatValue()) ; + case T_double: return Constant.fromValue(left.floatValue() - right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.floatValue() - right.byteValue()) ; + case T_short: return Constant.fromValue(left.floatValue() - right.shortValue()) ; + case T_int: return Constant.fromValue(left.floatValue() - right.intValue()) ; + case T_long: return Constant.fromValue(left.floatValue() - right.longValue()) ;} + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() - right.charValue()) ; + case T_float: return Constant.fromValue(left.doubleValue() - right.floatValue()) ; + case T_double: return Constant.fromValue(left.doubleValue() - right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.doubleValue() - right.byteValue()) ; + case T_short: return Constant.fromValue(left.doubleValue() - right.shortValue()) ; + case T_int: return Constant.fromValue(left.doubleValue() - right.intValue()) ; + case T_long: return Constant.fromValue(left.doubleValue() - right.longValue()) ;} + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() - right.charValue()) ; + case T_float: return Constant.fromValue(left.byteValue() - right.floatValue()) ; + case T_double: return Constant.fromValue(left.byteValue() - right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.byteValue() - right.byteValue()) ; + case T_short: return Constant.fromValue(left.byteValue() - right.shortValue()) ; + case T_int: return Constant.fromValue(left.byteValue() - right.intValue()) ; + case T_long: return Constant.fromValue(left.byteValue() - right.longValue()) ;} + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() - right.charValue()) ; + case T_float: return Constant.fromValue(left.shortValue() - right.floatValue()) ; + case T_double: return Constant.fromValue(left.shortValue() - right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.shortValue() - right.byteValue()) ; + case T_short: return Constant.fromValue(left.shortValue() - right.shortValue()) ; + case T_int: return Constant.fromValue(left.shortValue() - right.intValue()) ; + case T_long: return Constant.fromValue(left.shortValue() - right.longValue()) ;} + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() - right.charValue()) ; + case T_float: return Constant.fromValue(left.intValue() - right.floatValue()) ; + case T_double: return Constant.fromValue(left.intValue() - right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.intValue() - right.byteValue()) ; + case T_short: return Constant.fromValue(left.intValue() - right.shortValue()) ; + case T_int: return Constant.fromValue(left.intValue() - right.intValue()) ; + case T_long: return Constant.fromValue(left.intValue() - right.longValue()) ;} + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() - right.charValue()) ; + case T_float: return Constant.fromValue(left.longValue() - right.floatValue()) ; + case T_double: return Constant.fromValue(left.longValue() - right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.longValue() - right.byteValue()) ; + case T_short: return Constant.fromValue(left.longValue() - right.shortValue()) ; + case T_int: return Constant.fromValue(left.longValue() - right.intValue()) ; + case T_long: return Constant.fromValue(left.longValue() - right.longValue()) ;} + + } + + return NotAConstant ;} //should not get here +public static final Constant computeConstantOperationMULTIPLY(Constant left, int leftId, int operator, Constant right, int rightId) { + //this method assumes that the TC has been done . + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() * right.charValue()) ; + case T_float: return Constant.fromValue(left.charValue() * right.floatValue()) ; + case T_double: return Constant.fromValue(left.charValue() * right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.charValue() * right.byteValue()) ; + case T_short: return Constant.fromValue(left.charValue() * right.shortValue()) ; + case T_int: return Constant.fromValue(left.charValue() * right.intValue()) ; + case T_long: return Constant.fromValue(left.charValue() * right.longValue()) ;} + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() * right.charValue()) ; + case T_float: return Constant.fromValue(left.floatValue() * right.floatValue()) ; + case T_double: return Constant.fromValue(left.floatValue() * right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.floatValue() * right.byteValue()) ; + case T_short: return Constant.fromValue(left.floatValue() * right.shortValue()) ; + case T_int: return Constant.fromValue(left.floatValue() * right.intValue()) ; + case T_long: return Constant.fromValue(left.floatValue() * right.longValue()) ;} + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() * right.charValue()) ; + case T_float: return Constant.fromValue(left.doubleValue() * right.floatValue()) ; + case T_double: return Constant.fromValue(left.doubleValue() * right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.doubleValue() * right.byteValue()) ; + case T_short: return Constant.fromValue(left.doubleValue() * right.shortValue()) ; + case T_int: return Constant.fromValue(left.doubleValue() * right.intValue()) ; + case T_long: return Constant.fromValue(left.doubleValue() * right.longValue()) ;} + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() * right.charValue()) ; + case T_float: return Constant.fromValue(left.byteValue() * right.floatValue()) ; + case T_double: return Constant.fromValue(left.byteValue() * right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.byteValue() * right.byteValue()) ; + case T_short: return Constant.fromValue(left.byteValue() * right.shortValue()) ; + case T_int: return Constant.fromValue(left.byteValue() * right.intValue()) ; + case T_long: return Constant.fromValue(left.byteValue() * right.longValue()) ;} + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() * right.charValue()) ; + case T_float: return Constant.fromValue(left.shortValue() * right.floatValue()) ; + case T_double: return Constant.fromValue(left.shortValue() * right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.shortValue() * right.byteValue()) ; + case T_short: return Constant.fromValue(left.shortValue() * right.shortValue()) ; + case T_int: return Constant.fromValue(left.shortValue() * right.intValue()) ; + case T_long: return Constant.fromValue(left.shortValue() * right.longValue()) ;} + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() * right.charValue()) ; + case T_float: return Constant.fromValue(left.intValue() * right.floatValue()) ; + case T_double: return Constant.fromValue(left.intValue() * right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.intValue() * right.byteValue()) ; + case T_short: return Constant.fromValue(left.intValue() * right.shortValue()) ; + case T_int: return Constant.fromValue(left.intValue() * right.intValue()) ; + case T_long: return Constant.fromValue(left.intValue() * right.longValue()) ;} + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() * right.charValue()) ; + case T_float: return Constant.fromValue(left.longValue() * right.floatValue()) ; + case T_double: return Constant.fromValue(left.longValue() * right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.longValue() * right.byteValue()) ; + case T_short: return Constant.fromValue(left.longValue() * right.shortValue()) ; + case T_int: return Constant.fromValue(left.longValue() * right.intValue()) ; + case T_long: return Constant.fromValue(left.longValue() * right.longValue()) ;} + + } + + + return NotAConstant ;} //should not get here +public static final Constant computeConstantOperationOR(Constant left, int leftId, int operator, Constant right, int rightId) { + //this method assumes that the TC has been done . + + switch (leftId){ + case T_boolean : return Constant.fromValue(left.booleanValue() | right.booleanValue()) ; + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() | right.charValue()) ; + case T_byte: return Constant.fromValue(left.charValue() | right.byteValue()) ; + case T_short: return Constant.fromValue(left.charValue() | right.shortValue()) ; + case T_int: return Constant.fromValue(left.charValue() | right.intValue()) ; + case T_long: return Constant.fromValue(left.charValue() | right.longValue()) ;} + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() | right.charValue()) ; + case T_byte: return Constant.fromValue(left.byteValue() | right.byteValue()) ; + case T_short: return Constant.fromValue(left.byteValue() | right.shortValue()) ; + case T_int: return Constant.fromValue(left.byteValue() | right.intValue()) ; + case T_long: return Constant.fromValue(left.byteValue() | right.longValue()) ;} + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() | right.charValue()) ; + case T_byte: return Constant.fromValue(left.shortValue() | right.byteValue()) ; + case T_short: return Constant.fromValue(left.shortValue() | right.shortValue()) ; + case T_int: return Constant.fromValue(left.shortValue() | right.intValue()) ; + case T_long: return Constant.fromValue(left.shortValue() | right.longValue()) ;} + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() | right.charValue()) ; + case T_byte: return Constant.fromValue(left.intValue() | right.byteValue()) ; + case T_short: return Constant.fromValue(left.intValue() | right.shortValue()) ; + case T_int: return Constant.fromValue(left.intValue() | right.intValue()) ; + case T_long: return Constant.fromValue(left.intValue() | right.longValue()) ;} + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() | right.charValue()) ; + case T_byte: return Constant.fromValue(left.longValue() | right.byteValue()) ; + case T_short: return Constant.fromValue(left.longValue() | right.shortValue()) ; + case T_int: return Constant.fromValue(left.longValue() | right.intValue()) ; + case T_long: return Constant.fromValue(left.longValue() | right.longValue()) ;} + + } + + + return NotAConstant ;} // should not get here +public static final Constant computeConstantOperationOR_OR(Constant left, int leftId, int operator, Constant right, int rightId) { + //this method assumes that the TC has been done . + + return Constant.fromValue(left.booleanValue() || right.booleanValue()) ;} +public static final Constant computeConstantOperationPLUS(Constant left, int leftId, int operator, Constant right, int rightId) { + //this method assumes that the TC has been done . + + switch (leftId){ + case T_Object : + if (rightId == T_String) { + return Constant.fromValue(left.stringValue() + right.stringValue()); + } + case T_boolean : + if (rightId == T_String) { + return Constant.fromValue(left.stringValue() + right.stringValue()); + } + break ; + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() + right.charValue()) ; + case T_float: return Constant.fromValue(left.charValue() + right.floatValue()) ; + case T_double: return Constant.fromValue(left.charValue() + right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.charValue() + right.byteValue()) ; + case T_short: return Constant.fromValue(left.charValue() + right.shortValue()) ; + case T_int: return Constant.fromValue(left.charValue() + right.intValue()) ; + case T_long: return Constant.fromValue(left.charValue() + right.longValue()) ; + case T_String: return Constant.fromValue(left.stringValue() + right.stringValue()) ;} + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() + right.charValue()) ; + case T_float: return Constant.fromValue(left.floatValue() + right.floatValue()) ; + case T_double: return Constant.fromValue(left.floatValue() + right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.floatValue() + right.byteValue()) ; + case T_short: return Constant.fromValue(left.floatValue() + right.shortValue()) ; + case T_int: return Constant.fromValue(left.floatValue() + right.intValue()) ; + case T_long: return Constant.fromValue(left.floatValue() + right.longValue()) ; + case T_String: return Constant.fromValue(left.stringValue() + right.stringValue()) ; } + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() + right.charValue()) ; + case T_float: return Constant.fromValue(left.doubleValue() + right.floatValue()) ; + case T_double: return Constant.fromValue(left.doubleValue() + right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.doubleValue() + right.byteValue()) ; + case T_short: return Constant.fromValue(left.doubleValue() + right.shortValue()) ; + case T_int: return Constant.fromValue(left.doubleValue() + right.intValue()) ; + case T_long: return Constant.fromValue(left.doubleValue() + right.longValue()) ; + case T_String: return Constant.fromValue(left.stringValue() + right.stringValue()) ;} + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() + right.charValue()) ; + case T_float: return Constant.fromValue(left.byteValue() + right.floatValue()) ; + case T_double: return Constant.fromValue(left.byteValue() + right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.byteValue() + right.byteValue()) ; + case T_short: return Constant.fromValue(left.byteValue() + right.shortValue()) ; + case T_int: return Constant.fromValue(left.byteValue() + right.intValue()) ; + case T_long: return Constant.fromValue(left.byteValue() + right.longValue()) ; + case T_String: return Constant.fromValue(left.stringValue() + right.stringValue()) ; } + + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() + right.charValue()) ; + case T_float: return Constant.fromValue(left.shortValue() + right.floatValue()) ; + case T_double: return Constant.fromValue(left.shortValue() + right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.shortValue() + right.byteValue()) ; + case T_short: return Constant.fromValue(left.shortValue() + right.shortValue()) ; + case T_int: return Constant.fromValue(left.shortValue() + right.intValue()) ; + case T_long: return Constant.fromValue(left.shortValue() + right.longValue()) ; + case T_String: return Constant.fromValue(left.stringValue() + right.stringValue()) ;} + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() + right.charValue()) ; + case T_float: return Constant.fromValue(left.intValue() + right.floatValue()) ; + case T_double: return Constant.fromValue(left.intValue() + right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.intValue() + right.byteValue()) ; + case T_short: return Constant.fromValue(left.intValue() + right.shortValue()) ; + case T_int: return Constant.fromValue(left.intValue() + right.intValue()) ; + case T_long: return Constant.fromValue(left.intValue() + right.longValue()) ; + case T_String: return Constant.fromValue(left.stringValue() + right.stringValue()) ;} + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() + right.charValue()) ; + case T_float: return Constant.fromValue(left.longValue() + right.floatValue()) ; + case T_double: return Constant.fromValue(left.longValue() + right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.longValue() + right.byteValue()) ; + case T_short: return Constant.fromValue(left.longValue() + right.shortValue()) ; + case T_int: return Constant.fromValue(left.longValue() + right.intValue()) ; + case T_long: return Constant.fromValue(left.longValue() + right.longValue()) ; + case T_String: return Constant.fromValue(left.stringValue() + right.stringValue()) ; } + break; + case T_String : + switch (rightId){ + case T_char : return Constant.fromValue(left.stringValue() + right.stringValue()) ; + case T_float: return Constant.fromValue(left.stringValue() + right.stringValue()) ; + case T_double: return Constant.fromValue(left.stringValue() + right.stringValue()) ; + case T_byte: return Constant.fromValue(left.stringValue() + right.stringValue()) ; + case T_short: return Constant.fromValue(left.stringValue() + right.stringValue()) ; + case T_int: return Constant.fromValue(left.stringValue() + right.stringValue()) ; + case T_long: return Constant.fromValue(left.stringValue() + right.stringValue()) ; + case T_String: return Constant.fromValue(left.stringValue() + right.stringValue()) ; + case T_null: return Constant.fromValue(left.stringValue() + right.stringValue()) ; + case T_boolean: return Constant.fromValue(left.stringValue() + right.stringValue()) ;} + break; + case T_null : + switch (rightId){ + case T_char : return Constant.fromValue(left.stringValue() + right.stringValue()) ; + case T_float: return Constant.fromValue(left.stringValue() + right.stringValue()) ; + case T_double: return Constant.fromValue(left.stringValue() + right.stringValue()) ; + case T_byte: return Constant.fromValue(left.stringValue() + right.stringValue()) ; + case T_short: return Constant.fromValue(left.stringValue() + right.stringValue()) ; + case T_int: return Constant.fromValue(left.stringValue() + right.stringValue()) ; + case T_long: return Constant.fromValue(left.stringValue() + right.stringValue()) ; + case T_String: return Constant.fromValue(left.stringValue() + right.stringValue()) ; + case T_null: return Constant.fromValue(left.stringValue() + right.stringValue()) ; } + + } + + return NotAConstant ;} //should not get here +public static final Constant computeConstantOperationREMAINDER(Constant left, int leftId, int operator, Constant right, int rightId) { + //this method assumes that the TC has been done . + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() % right.charValue()) ; + case T_float: return Constant.fromValue(left.charValue() % right.floatValue()) ; + case T_double: return Constant.fromValue(left.charValue() % right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.charValue() % right.byteValue()) ; + case T_short: return Constant.fromValue(left.charValue() % right.shortValue()) ; + case T_int: return Constant.fromValue(left.charValue() % right.intValue()) ; + case T_long: return Constant.fromValue(left.charValue() % right.longValue()) ;} + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() % right.charValue()) ; + case T_float: return Constant.fromValue(left.floatValue() % right.floatValue()) ; + case T_double: return Constant.fromValue(left.floatValue() % right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.floatValue() % right.byteValue()) ; + case T_short: return Constant.fromValue(left.floatValue() % right.shortValue()) ; + case T_int: return Constant.fromValue(left.floatValue() % right.intValue()) ; + case T_long: return Constant.fromValue(left.floatValue() % right.longValue()) ;} + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() % right.charValue()) ; + case T_float: return Constant.fromValue(left.doubleValue() % right.floatValue()) ; + case T_double: return Constant.fromValue(left.doubleValue() % right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.doubleValue() % right.byteValue()) ; + case T_short: return Constant.fromValue(left.doubleValue() % right.shortValue()) ; + case T_int: return Constant.fromValue(left.doubleValue() % right.intValue()) ; + case T_long: return Constant.fromValue(left.doubleValue() % right.longValue()) ;} + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() % right.charValue()) ; + case T_float: return Constant.fromValue(left.byteValue() % right.floatValue()) ; + case T_double: return Constant.fromValue(left.byteValue() % right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.byteValue() % right.byteValue()) ; + case T_short: return Constant.fromValue(left.byteValue() % right.shortValue()) ; + case T_int: return Constant.fromValue(left.byteValue() % right.intValue()) ; + case T_long: return Constant.fromValue(left.byteValue() % right.longValue()) ;} + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() % right.charValue()) ; + case T_float: return Constant.fromValue(left.shortValue() % right.floatValue()) ; + case T_double: return Constant.fromValue(left.shortValue() % right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.shortValue() % right.byteValue()) ; + case T_short: return Constant.fromValue(left.shortValue() % right.shortValue()) ; + case T_int: return Constant.fromValue(left.shortValue() % right.intValue()) ; + case T_long: return Constant.fromValue(left.shortValue() % right.longValue()) ;} + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() % right.charValue()) ; + case T_float: return Constant.fromValue(left.intValue() % right.floatValue()) ; + case T_double: return Constant.fromValue(left.intValue() % right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.intValue() % right.byteValue()) ; + case T_short: return Constant.fromValue(left.intValue() % right.shortValue()) ; + case T_int: return Constant.fromValue(left.intValue() % right.intValue()) ; + case T_long: return Constant.fromValue(left.intValue() % right.longValue()) ;} + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() % right.charValue()) ; + case T_float: return Constant.fromValue(left.longValue() % right.floatValue()) ; + case T_double: return Constant.fromValue(left.longValue() % right.doubleValue()) ; + case T_byte: return Constant.fromValue(left.longValue() % right.byteValue()) ; + case T_short: return Constant.fromValue(left.longValue() % right.shortValue()) ; + case T_int: return Constant.fromValue(left.longValue() % right.intValue()) ; + case T_long: return Constant.fromValue(left.longValue() % right.longValue()) ;} + + } + + return NotAConstant ;} //should not get here +public static final Constant computeConstantOperationRIGHT_SHIFT(Constant left, int leftId, int operator, Constant right, int rightId) { + //this method assumes that the TC has been done . + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() >> right.charValue()) ; + case T_byte: return Constant.fromValue(left.charValue() >> right.byteValue()) ; + case T_short: return Constant.fromValue(left.charValue() >> right.shortValue()) ; + case T_int: return Constant.fromValue(left.charValue() >> right.intValue()) ; + case T_long: return Constant.fromValue(left.charValue() >> right.longValue()) ;} + break ; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() >> right.charValue()) ; + case T_byte: return Constant.fromValue(left.byteValue() >> right.byteValue()) ; + case T_short: return Constant.fromValue(left.byteValue() >> right.shortValue()) ; + case T_int: return Constant.fromValue(left.byteValue() >> right.intValue()) ; + case T_long: return Constant.fromValue(left.byteValue() >> right.longValue()) ;} + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() >> right.charValue()) ; + case T_byte: return Constant.fromValue(left.shortValue() >> right.byteValue()) ; + case T_short: return Constant.fromValue(left.shortValue() >> right.shortValue()) ; + case T_int: return Constant.fromValue(left.shortValue() >> right.intValue()) ; + case T_long: return Constant.fromValue(left.shortValue() >> right.longValue()) ;} + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() >> right.charValue()) ; + case T_byte: return Constant.fromValue(left.intValue() >> right.byteValue()) ; + case T_short: return Constant.fromValue(left.intValue() >> right.shortValue()) ; + case T_int: return Constant.fromValue(left.intValue() >> right.intValue()) ; + case T_long: return Constant.fromValue(left.intValue() >> right.longValue()) ;} + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() >> right.charValue()) ; + case T_byte: return Constant.fromValue(left.longValue() >> right.byteValue()) ; + case T_short: return Constant.fromValue(left.longValue() >> right.shortValue()) ; + case T_int: return Constant.fromValue(left.longValue() >> right.intValue()) ; + case T_long: return Constant.fromValue(left.longValue() >> right.longValue()) ;} + + } + + + return NotAConstant ;} // should not get here +public static final Constant computeConstantOperationUNSIGNED_RIGHT_SHIFT(Constant left, int leftId, int operator, Constant right, int rightId) { + //this method assumes that the TC has been done . + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() >>> right.charValue()) ; + case T_byte: return Constant.fromValue(left.charValue() >>> right.byteValue()) ; + case T_short: return Constant.fromValue(left.charValue() >>> right.shortValue()) ; + case T_int: return Constant.fromValue(left.charValue() >>> right.intValue()) ; + case T_long: return Constant.fromValue(left.charValue() >>> right.longValue()) ;} + break ; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() >>> right.charValue()) ; + case T_byte: return Constant.fromValue(left.byteValue() >>> right.byteValue()) ; + case T_short: return Constant.fromValue(left.byteValue() >>> right.shortValue()) ; + case T_int: return Constant.fromValue(left.byteValue() >>> right.intValue()) ; + case T_long: return Constant.fromValue(left.byteValue() >>> right.longValue()) ;} + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() >>> right.charValue()) ; + case T_byte: return Constant.fromValue(left.shortValue() >>> right.byteValue()) ; + case T_short: return Constant.fromValue(left.shortValue() >>> right.shortValue()) ; + case T_int: return Constant.fromValue(left.shortValue() >>> right.intValue()) ; + case T_long: return Constant.fromValue(left.shortValue() >>> right.longValue()) ;} + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() >>> right.charValue()) ; + case T_byte: return Constant.fromValue(left.intValue() >>> right.byteValue()) ; + case T_short: return Constant.fromValue(left.intValue() >>> right.shortValue()) ; + case T_int: return Constant.fromValue(left.intValue() >>> right.intValue()) ; + case T_long: return Constant.fromValue(left.intValue() >>> right.longValue()) ;} + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() >>> right.charValue()) ; + case T_byte: return Constant.fromValue(left.longValue() >>> right.byteValue()) ; + case T_short: return Constant.fromValue(left.longValue() >>> right.shortValue()) ; + case T_int: return Constant.fromValue(left.longValue() >>> right.intValue()) ; + case T_long: return Constant.fromValue(left.longValue() >>> right.longValue()) ;} + + } + + + return NotAConstant ;} // should not get here +public static final Constant computeConstantOperationXOR(Constant left, int leftId, int operator, Constant right, int rightId) { + //this method assumes that the TC has been done . + + switch (leftId){ + case T_boolean : return Constant.fromValue(left.booleanValue() ^ right.booleanValue()) ; + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() ^ right.charValue()) ; + case T_byte: return Constant.fromValue(left.charValue() ^ right.byteValue()) ; + case T_short: return Constant.fromValue(left.charValue() ^ right.shortValue()) ; + case T_int: return Constant.fromValue(left.charValue() ^ right.intValue()) ; + case T_long: return Constant.fromValue(left.charValue() ^ right.longValue()) ;} + break ; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() ^ right.charValue()) ; + case T_byte: return Constant.fromValue(left.byteValue() ^ right.byteValue()) ; + case T_short: return Constant.fromValue(left.byteValue() ^ right.shortValue()) ; + case T_int: return Constant.fromValue(left.byteValue() ^ right.intValue()) ; + case T_long: return Constant.fromValue(left.byteValue() ^ right.longValue()) ;} + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() ^ right.charValue()) ; + case T_byte: return Constant.fromValue(left.shortValue() ^ right.byteValue()) ; + case T_short: return Constant.fromValue(left.shortValue() ^ right.shortValue()) ; + case T_int: return Constant.fromValue(left.shortValue() ^ right.intValue()) ; + case T_long: return Constant.fromValue(left.shortValue() ^ right.longValue()) ;} + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() ^ right.charValue()) ; + case T_byte: return Constant.fromValue(left.intValue() ^ right.byteValue()) ; + case T_short: return Constant.fromValue(left.intValue() ^ right.shortValue()) ; + case T_int: return Constant.fromValue(left.intValue() ^ right.intValue()) ; + case T_long: return Constant.fromValue(left.intValue() ^ right.longValue()) ;} + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() ^ right.charValue()) ; + case T_byte: return Constant.fromValue(left.longValue() ^ right.byteValue()) ; + case T_short: return Constant.fromValue(left.longValue() ^ right.shortValue()) ; + case T_int: return Constant.fromValue(left.longValue() ^ right.intValue()) ; + case T_long: return Constant.fromValue(left.longValue() ^ right.longValue()) ;} + + } + + + return NotAConstant ;} // should not get here +public double doubleValue() { + throw new ShouldNotImplement(Util.bind("constant.cannotCastedInto",typeName(),"double")); //$NON-NLS-2$ //$NON-NLS-1$ +} +public float floatValue() { + throw new ShouldNotImplement(Util.bind("constant.cannotCastedInto",typeName(),"float")); //$NON-NLS-2$ //$NON-NLS-1$ +} +public static Constant fromValue(byte value) { + return new ByteConstant(value); +} +public static Constant fromValue(char value) { + return new CharConstant(value); +} +public static Constant fromValue(double value) { + return new DoubleConstant(value); +} +public static Constant fromValue(float value) { + return new FloatConstant(value); +} +public static Constant fromValue(int value) { + return new IntConstant(value); +} +public static Constant fromValue(long value) { + return new LongConstant(value); +} +public static Constant fromValue(String value) { + if (value == null) return NullConstant.Default; + return new StringConstant(value); +} +public static Constant fromValue(short value) { + return new ShortConstant(value); +} +public static Constant fromValue(boolean value) { + return new BooleanConstant(value); +} +public int intValue() { + throw new ShouldNotImplement(Util.bind("constant.cannotCastedInto",typeName(),"int")); //$NON-NLS-2$ //$NON-NLS-1$ +} +public long longValue() { + throw new ShouldNotImplement(Util.bind("constant.cannotCastedInto",typeName(),"long")); //$NON-NLS-2$ //$NON-NLS-1$ +} +public short shortValue() { + throw new ShouldNotImplement(Util.bind("constant.cannotConvertedTo",typeName(),"short")); //$NON-NLS-2$ //$NON-NLS-1$ +} +/** Deprecated +*/ +public String stringValue() { + throw new ShouldNotImplement(Util.bind("constant.cannotConvertedTo",typeName(),"String")); //$NON-NLS-1$ //$NON-NLS-2$ +} +public String toString(){ + + if (this == NotAConstant) return "(Constant) NotAConstant" ; //$NON-NLS-1$ + return super.toString(); } +public abstract int typeID(); +public String typeName() { + switch (typeID()) { + case T_int : return "int"; //$NON-NLS-1$ + case T_byte : return "byte"; //$NON-NLS-1$ + case T_short : return "short"; //$NON-NLS-1$ + case T_char : return "char"; //$NON-NLS-1$ + case T_float : return "float"; //$NON-NLS-1$ + case T_double : return "double"; //$NON-NLS-1$ + case T_boolean : return "boolean"; //$NON-NLS-1$ + case T_long : return "long";//$NON-NLS-1$ + case T_String : return "java.lang.String"; //$NON-NLS-1$ + case T_null : return "null"; //$NON-NLS-1$ + default: return "unknown"; //$NON-NLS-1$ + } +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/DoubleConstant.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/DoubleConstant.java new file mode 100644 index 0000000..e92ddb7 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/DoubleConstant.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.impl; + +public class DoubleConstant extends Constant { + + double value; + + public DoubleConstant(double value) { + this.value = value; + } + + public byte byteValue() { + return (byte) value; + } + + public char charValue() { + return (char) value; + } + + public double doubleValue() { + return (double) value; + } + + public float floatValue() { + return (float) value; + } + + public int intValue() { + return (int) value; + } + + public long longValue() { + return (long) value; + } + + public short shortValue() { + return (short) value; + } + + public String stringValue() { + //spec 15.17.11 + String s = new Double(value).toString(); + if (s == null) + return "null"; //$NON-NLS-1$ + else + return s; + } + + public String toString() { + if (this == NotAConstant) + return "(Constant) NotAConstant"; //$NON-NLS-1$ + return "(double)" + value; //$NON-NLS-1$ + } + + public int typeID() { + return T_double; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/FloatConstant.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/FloatConstant.java new file mode 100644 index 0000000..92570bc --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/FloatConstant.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.impl; + +public class FloatConstant extends Constant { + + float value; + + public FloatConstant(float value) { + this.value = value; + } + + public byte byteValue() { + return (byte) value; + } + + public char charValue() { + return (char) value; + } + + public double doubleValue() { + return (double) value; + } + + public float floatValue() { + return (float) value; + } + + public int intValue() { + return (int) value; + } + + public long longValue() { + return (long) value; + } + + public short shortValue() { + return (short) value; + } + + public String stringValue() { + //spec 15.17.11 + String s = new Float(value).toString(); + if (s == null) + return "null"; //$NON-NLS-1$ + else + return s; + } + + public String toString() { + return "(float)" + value; //$NON-NLS-1$ + } + + public int typeID() { + return T_float; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/ITypeRequestor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/ITypeRequestor.java new file mode 100644 index 0000000..6bb4bd1 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/ITypeRequestor.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.impl; + +import net.sourceforge.phpdt.internal.compiler.env.IBinaryType; +import net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit; +import net.sourceforge.phpdt.internal.compiler.env.ISourceType; +import net.sourceforge.phpdt.internal.compiler.lookup.PackageBinding; + + +public interface ITypeRequestor { + + /** + * Accept the resolved binary form for the requested type. + */ + void accept(IBinaryType binaryType, PackageBinding packageBinding); + + /** + * Accept the requested type's compilation unit. + */ + void accept(ICompilationUnit unit); + + /** + * Accept the unresolved source forms for the requested type. + * Note that the multiple source forms can be answered, in case the target compilation unit + * contains multiple types. The first one is then guaranteed to be the one corresponding to the + * requested type. + */ + void accept(ISourceType[] sourceType, PackageBinding packageBinding); +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/IntConstant.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/IntConstant.java new file mode 100644 index 0000000..819072b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/IntConstant.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.impl; + +public class IntConstant extends Constant { + + int value; + + public IntConstant(int value) { + this.value = value; + } + + public byte byteValue() { + return (byte) value; + } + + public char charValue() { + return (char) value; + } + + public double doubleValue() { + return (double) value; + } + + public float floatValue() { + return (float) value; + } + + public int intValue() { + return (int) value; + } + + public long longValue() { + return (long) value; + } + + public short shortValue() { + return (short) value; + } + + public String stringValue() { + //spec 15.17.11 + String s = new Integer(value).toString(); + if (s == null) + return "null"; //$NON-NLS-1$ + else + return s; + } + + public String toString() { + return "(int)" + value; //$NON-NLS-1$ + } + + public int typeID() { + return T_int; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/LongConstant.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/LongConstant.java new file mode 100644 index 0000000..5e6bdaf --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/LongConstant.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.impl; + +public class LongConstant extends Constant { + long value; +public LongConstant(long value) { + this.value = value; +} +public byte byteValue() { + return (byte) value; +} +public char charValue() { + return (char) value; +} +public double doubleValue() { + return (double) value; +} +public float floatValue() { + return (float) value; +} +public int intValue() { + return (int) value; +} +public long longValue() { + return (long) value; +} +public short shortValue() { + return (short) value; +} +public String stringValue() { + //spec 15.17.11 + + String s = new Long(value).toString() ; + if (s == null) + return "null"; //$NON-NLS-1$ + else + return s; +} +public String toString(){ + + return "(long)" + value ; } //$NON-NLS-1$ +public int typeID() { + return T_long; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/NullConstant.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/NullConstant.java new file mode 100644 index 0000000..b200685 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/NullConstant.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.impl; + +public class NullConstant extends Constant { + public static final NullConstant Default = new NullConstant(); + + final static String NullString = new StringBuffer(4).append((String)null).toString(); +private NullConstant() { +} +public String stringValue() { + + return NullString; +} +public String toString(){ + + return "(null)" + null ; } //$NON-NLS-1$ +public int typeID() { + return T_null; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/ReferenceContext.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/ReferenceContext.java new file mode 100644 index 0000000..e14a97a --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/ReferenceContext.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.impl; +/* + * Implementors are valid compilation contexts from which we can + * escape in case of error: + * i.e. method | type | compilation unit + */ + +import net.sourceforge.phpdt.internal.compiler.CompilationResult; + +public interface ReferenceContext { + void abort(int abortLevel); + CompilationResult compilationResult(); + void tagAsHavingErrors(); + boolean hasErrors(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/ShortConstant.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/ShortConstant.java new file mode 100644 index 0000000..d711901 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/ShortConstant.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.impl; + +public class ShortConstant extends Constant { + short value; +public ShortConstant(short value) { + this.value = value; +} +public byte byteValue() { + return (byte) value; +} +public char charValue() { + return (char) value; +} +public double doubleValue() { + return (double) value; +} +public float floatValue() { + return (float) value; +} +public int intValue() { + return (int) value; +} +public long longValue() { + return (long) value; +} +public short shortValue() { + return (short) value; +} +public String stringValue() { + //spec 15.17.11 + + String s = new Integer(value).toString() ; + if (s == null) + return "null"; //$NON-NLS-1$ + else + return s; +} +public String toString(){ + + return "(short)" + value ; } //$NON-NLS-1$ +public int typeID() { + return T_short; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/StringConstant.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/StringConstant.java new file mode 100644 index 0000000..c034eb1 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/impl/StringConstant.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.impl; + +public class StringConstant extends Constant { + public String value; + +public StringConstant(String value) { + this.value = value ; +} +public boolean compileTimeEqual(StringConstant right){ + //String are intermed in the compiler==>thus if two string constant + //get to be compared, it is an equal on the vale which is done + if (this.value == null) { + return right.value == null; + } + return this.value.equals(right.value); +} +public String stringValue() { + //spec 15.17.11 + + //the next line do not go into the toString() send....! + return value ; + + /* + String s = value.toString() ; + if (s == null) + return "null"; + else + return s; + */ + +} +public String toString(){ + + return "(String)\"" + value +"\""; } //$NON-NLS-2$ //$NON-NLS-1$ +public int typeID() { + return T_String; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ArrayBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ArrayBinding.java new file mode 100644 index 0000000..ab938cb --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ArrayBinding.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.impl.Constant; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public final class ArrayBinding extends TypeBinding { + // creation and initialization of the length field + // the declaringClass of this field is intentionally set to null so it can be distinguished. + public static final FieldBinding LengthField = new FieldBinding(LENGTH, IntBinding, AccPublic | AccFinal, null, Constant.NotAConstant); + + public TypeBinding leafComponentType; + public int dimensions; + + char[] constantPoolName; +public ArrayBinding(TypeBinding type, int dimensions) { + this.tagBits |= IsArrayType; + this.leafComponentType = type; + this.dimensions = dimensions; +} +/* Answer the receiver's constant pool name. +* +* NOTE: This method should only be used during/after code gen. +*/ + +public char[] constantPoolName() /* [Ljava/lang/Object; */ { + if (constantPoolName != null) + return constantPoolName; + + char[] brackets = new char[dimensions]; + for (int i = dimensions - 1; i >= 0; i--) + brackets[i] = '['; + return constantPoolName = CharOperation.concat(brackets, leafComponentType.signature()); +} +String debugName() { + StringBuffer brackets = new StringBuffer(dimensions * 2); + for (int i = dimensions; --i >= 0;) + brackets.append("[]"); //$NON-NLS-1$ + return leafComponentType.debugName() + brackets.toString(); +} +/* Answer an array whose dimension size is one less than the receiver. +* +* When the receiver's dimension size is one then answer the leaf component type. +*/ + +public TypeBinding elementsType(Scope scope) { + if (dimensions == 1) + return leafComponentType; + else + return scope.createArray(leafComponentType, dimensions - 1); +} +public PackageBinding getPackage() { + return leafComponentType.getPackage(); +} +/* Answer true if the receiver type can be assigned to the argument type (right) +*/ + +boolean isCompatibleWith(TypeBinding right) { + if (this == right) + return true; + + char[][] rightName; + if (right.isArrayType()) { + ArrayBinding rightArray = (ArrayBinding) right; + if (rightArray.leafComponentType.isBaseType()) + return false; // relying on the fact that all equal arrays are identical + if (dimensions == rightArray.dimensions) + return leafComponentType.isCompatibleWith(rightArray.leafComponentType); + if (dimensions < rightArray.dimensions) + return false; // cannot assign 'String[]' into 'Object[][]' but can assign 'byte[][]' into 'Object[]' + rightName = ((ReferenceBinding) rightArray.leafComponentType).compoundName; + } else { + if (right.isBaseType()) + return false; + rightName = ((ReferenceBinding) right).compoundName; + } + //Check dimensions - Java does not support explicitly sized dimensions for types. + //However, if it did, the type checking support would go here. + + if (CharOperation.equals(rightName, JAVA_LANG_OBJECT)) + return true; + if (CharOperation.equals(rightName, JAVA_LANG_CLONEABLE)) + return true; + if (CharOperation.equals(rightName, JAVA_IO_SERIALIZABLE)) + return true; + return false; +} + +public TypeBinding leafComponentType(){ + return leafComponentType; +} + +/* API +* Answer the problem id associated with the receiver. +* NoError if the receiver is a valid binding. +*/ + +public int problemId() { + return leafComponentType.problemId(); +} +/** +* Answer the source name for the type. +* In the case of member types, as the qualified name from its top level type. +* For example, for a member type N defined inside M & A: "A.M.N". +*/ + +public char[] qualifiedSourceName() { + char[] brackets = new char[dimensions * 2]; + for (int i = dimensions * 2 - 1; i >= 0; i -= 2) { + brackets[i] = ']'; + brackets[i - 1] = '['; + } + return CharOperation.concat(leafComponentType.qualifiedSourceName(), brackets); +} +public char[] readableName() /* java.lang.Object[] */ { + char[] brackets = new char[dimensions * 2]; + for (int i = dimensions * 2 - 1; i >= 0; i -= 2) { + brackets[i] = ']'; + brackets[i - 1] = '['; + } + return CharOperation.concat(leafComponentType.readableName(), brackets); +} +public char[] sourceName() { + char[] brackets = new char[dimensions * 2]; + for (int i = dimensions * 2 - 1; i >= 0; i -= 2) { + brackets[i] = ']'; + brackets[i - 1] = '['; + } + return CharOperation.concat(leafComponentType.sourceName(), brackets); +} +public String toString() { + return leafComponentType != null ? debugName() : "NULL TYPE ARRAY"; //$NON-NLS-1$ +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/BaseTypeBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/BaseTypeBinding.java new file mode 100644 index 0000000..a7cc33d --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/BaseTypeBinding.java @@ -0,0 +1,155 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +public final class BaseTypeBinding extends TypeBinding { + public char[] simpleName; + private char [] constantPoolName; +BaseTypeBinding(int id, char[] name, char[] constantPoolName) { + this.tagBits |= IsBaseType; + this.id = id; + this.simpleName = name; + this.constantPoolName = constantPoolName; +} +/* Answer the receiver's constant pool name. +*/ + +public char[] constantPoolName() { + return constantPoolName; +} +public PackageBinding getPackage() { + return null; +} +/* Answer true if the receiver type can be assigned to the argument type (right) +*/ + +final boolean isCompatibleWith(TypeBinding right) { + if (this == right) + return true; + if (!right.isBaseType()) + return this == NullBinding; + + switch (right.id) { + case T_boolean : + case T_byte : + case T_char : + return false; + case T_double : + switch (id) { + case T_byte : + case T_char : + case T_short : + case T_int : + case T_long : + case T_float : + return true; + default : + return false; + } + case T_float : + switch (id) { + case T_byte : + case T_char : + case T_short : + case T_int : + case T_long : + return true; + default : + return false; + } + case T_long : + switch (id) { + case T_byte : + case T_char : + case T_short : + case T_int : + return true; + default : + return false; + } + case T_int : + switch (id) { + case T_byte : + case T_char : + case T_short : + return true; + default : + return false; + } + case T_short : + return (id == T_byte); + } + return false; +} +public static final boolean isNarrowing(int left, int right) { + //can "left" store a "right" using some narrowing conversion + //(is left smaller than right) + + switch (left) { + case T_boolean : + return right == T_boolean; + case T_char : + case T_byte : + if (right == T_byte) return true; + case T_short : + if (right == T_short) return true; + if (right == T_char) return true; + case T_int : + if (right == T_int) return true; + case T_long : + if (right == T_long) return true; + case T_float : + if (right == T_float) return true; + case T_double : + if (right == T_double) return true; + default : + return false; + } +} +public static final boolean isWidening(int left, int right) { + //can "left" store a "right" using some widening conversion + //(is left "bigger" than right) + + switch (left) { + case T_boolean : + return right == T_boolean; + case T_char : + return right == T_char; + case T_double : + if (right == T_double) return true; + case T_float : + if (right == T_float) return true; + case T_long : + if (right == T_long) return true; + case T_int : + if (right == T_int) return true; + if (right == T_char) return true; + case T_short : + if (right == T_short) return true; + case T_byte : + if (right == T_byte) return true; + default : + return false; + } +} +public char[] qualifiedSourceName() { + return simpleName; +} +public char[] readableName() { + return simpleName; +} +public char[] sourceName() { + return simpleName; +} +public String toString() { + return new String(constantPoolName) + " (id=" + id + ")"; //$NON-NLS-1$ //$NON-NLS-2$ +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/BaseTypes.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/BaseTypes.java new file mode 100644 index 0000000..09c1293 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/BaseTypes.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +public interface BaseTypes { + final BaseTypeBinding IntBinding = new BaseTypeBinding(TypeIds.T_int, "int".toCharArray(), new char[] {'I'}); //$NON-NLS-1$ + final BaseTypeBinding ByteBinding = new BaseTypeBinding(TypeIds.T_byte, "byte".toCharArray(), new char[] {'B'}); //$NON-NLS-1$ + final BaseTypeBinding ShortBinding = new BaseTypeBinding(TypeIds.T_short, "short".toCharArray(), new char[] {'S'}); //$NON-NLS-1$ + final BaseTypeBinding CharBinding = new BaseTypeBinding(TypeIds.T_char, "char".toCharArray(), new char[] {'C'}); //$NON-NLS-1$ + final BaseTypeBinding LongBinding = new BaseTypeBinding(TypeIds.T_long, "long".toCharArray(), new char[] {'J'}); //$NON-NLS-1$ + final BaseTypeBinding FloatBinding = new BaseTypeBinding(TypeIds.T_float, "float".toCharArray(), new char[] {'F'}); //$NON-NLS-1$ + final BaseTypeBinding DoubleBinding = new BaseTypeBinding(TypeIds.T_double, "double".toCharArray(), new char[] {'D'}); //$NON-NLS-1$ + final BaseTypeBinding BooleanBinding = new BaseTypeBinding(TypeIds.T_boolean, "boolean".toCharArray(), new char[] {'Z'}); //$NON-NLS-1$ + final BaseTypeBinding NullBinding = new BaseTypeBinding(TypeIds.T_null, "null".toCharArray(), new char[] {'N'}); //N stands for null even if it is never internally used //$NON-NLS-1$ + final BaseTypeBinding VoidBinding = new BaseTypeBinding(TypeIds.T_void, "void".toCharArray(), new char[] {'V'}); //$NON-NLS-1$ +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/BinaryTypeBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/BinaryTypeBinding.java new file mode 100644 index 0000000..ee4fe85 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/BinaryTypeBinding.java @@ -0,0 +1,491 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration; +import net.sourceforge.phpdt.internal.compiler.env.IBinaryField; +import net.sourceforge.phpdt.internal.compiler.env.IBinaryMethod; +import net.sourceforge.phpdt.internal.compiler.env.IBinaryNestedType; +import net.sourceforge.phpdt.internal.compiler.env.IBinaryType; +import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +/* +Not all fields defined by this type are initialized when it is created. +Some are initialized only when needed. + +Accessors have been provided for some public fields so all TypeBindings have the same API... +but access public fields directly whenever possible. +Non-public fields have accessors which should be used everywhere you expect the field to be initialized. + +null is NOT a valid value for a non-public field... it just means the field is not initialized. +*/ + +public final class BinaryTypeBinding extends ReferenceBinding { + // all of these fields are ONLY guaranteed to be initialized if accessed using their public accessor method + private ReferenceBinding superclass; + private ReferenceBinding enclosingType; + private ReferenceBinding[] superInterfaces; + private FieldBinding[] fields; + private MethodBinding[] methods; + private ReferenceBinding[] memberTypes; + + // For the link with the principle structure + private LookupEnvironment environment; +public BinaryTypeBinding(PackageBinding packageBinding, IBinaryType binaryType, LookupEnvironment environment) { + this.compoundName = CharOperation.splitOn('/', binaryType.getName()); + computeId(); + + this.tagBits |= IsBinaryBinding; + this.environment = environment; + this.fPackage = packageBinding; + this. fileName = binaryType.getFileName(); + + // source name must be one name without "$". + char[] possibleSourceName = this.compoundName[this.compoundName.length - 1]; + int start = CharOperation.lastIndexOf('$', possibleSourceName) + 1; + if (start == 0) { + this.sourceName = possibleSourceName; + } else { + this.sourceName = new char[possibleSourceName.length - start]; + System.arraycopy(possibleSourceName, start, this.sourceName, 0, this.sourceName.length); + } + + this.modifiers = binaryType.getModifiers(); + if (binaryType.isInterface()) + this.modifiers |= AccInterface; +} + +public FieldBinding[] availableFields() { + FieldBinding[] availableFields = new FieldBinding[fields.length]; + int count = 0; + + for (int i = 0; i < fields.length;i++) { + try { + availableFields[count] = resolveTypeFor(fields[i]); + count++; + } catch (AbortCompilation a){ + } + } + + System.arraycopy(availableFields, 0, availableFields = new FieldBinding[count], 0, count); + return availableFields; +} + +public MethodBinding[] availableMethods() { + if ((modifiers & AccUnresolved) == 0) + return methods; + + MethodBinding[] availableMethods = new MethodBinding[methods.length]; + int count = 0; + + for (int i = 0; i < methods.length;i++) { + try { + availableMethods[count] = resolveTypesFor(methods[i]); + count++; + } catch (AbortCompilation a){ + } + } + System.arraycopy(availableMethods, 0, availableMethods = new MethodBinding[count], 0, count); + return availableMethods; +} + +void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) { + char[] superclassName = binaryType.getSuperclassName(); + if (superclassName != null) + // attempt to find the superclass if it exists in the cache (otherwise - resolve it when requested) + this.superclass = environment.getTypeFromConstantPoolName(superclassName, 0, -1); + + char[] enclosingTypeName = binaryType.getEnclosingTypeName(); + if (enclosingTypeName != null) { + // attempt to find the enclosing type if it exists in the cache (otherwise - resolve it when requested) + this.enclosingType = environment.getTypeFromConstantPoolName(enclosingTypeName, 0, -1); + this.tagBits |= MemberTypeMask; // must be a member type not a top-level or local type + if (this.enclosingType().isStrictfp()) + this.modifiers |= AccStrictfp; + if (this.enclosingType().isDeprecated()) + this.modifiers |= AccDeprecatedImplicitly; + } + + this.memberTypes = NoMemberTypes; + IBinaryNestedType[] memberTypeStructures = binaryType.getMemberTypes(); + if (memberTypeStructures != null) { + int size = memberTypeStructures.length; + if (size > 0) { + this.memberTypes = new ReferenceBinding[size]; + for (int i = 0; i < size; i++) + // attempt to find each member type if it exists in the cache (otherwise - resolve it when requested) + this.memberTypes[i] = environment.getTypeFromConstantPoolName(memberTypeStructures[i].getName(), 0, -1); + } + } + + this.superInterfaces = NoSuperInterfaces; + char[][] interfaceNames = binaryType.getInterfaceNames(); + if (interfaceNames != null) { + int size = interfaceNames.length; + if (size > 0) { + this.superInterfaces = new ReferenceBinding[size]; + for (int i = 0; i < size; i++) + // attempt to find each superinterface if it exists in the cache (otherwise - resolve it when requested) + this.superInterfaces[i] = environment.getTypeFromConstantPoolName(interfaceNames[i], 0, -1); + } + } + if (needFieldsAndMethods){ + createFields(binaryType.getFields()); + createMethods(binaryType.getMethods()); + } +} +private void createFields(IBinaryField[] iFields) { + this.fields = NoFields; + if (iFields != null) { + int size = iFields.length; + if (size > 0) { + this.fields = new FieldBinding[size]; + for (int i = 0; i < size; i++) { + IBinaryField field = iFields[i]; + this.fields[i] = + new FieldBinding( + field.getName(), + environment.getTypeFromSignature(field.getTypeName(), 0, -1), + field.getModifiers(), + this, + field.getConstant()); + } + } + } +} +private MethodBinding createMethod(IBinaryMethod method) { + int modifiers = method.getModifiers() | AccUnresolved; + + ReferenceBinding[] exceptions = NoExceptions; + char[][] exceptionTypes = method.getExceptionTypeNames(); + if (exceptionTypes != null) { + int size = exceptionTypes.length; + if (size > 0) { + exceptions = new ReferenceBinding[size]; + for (int i = 0; i < size; i++) + exceptions[i] = environment.getTypeFromConstantPoolName(exceptionTypes[i], 0, -1); + } + } + + TypeBinding[] parameters = NoParameters; + char[] signature = method.getMethodDescriptor(); // of the form (I[Ljava/jang/String;)V + int numOfParams = 0; + char nextChar; + int index = 0; // first character is always '(' so skip it + while ((nextChar = signature[++index]) != ')') { + if (nextChar != '[') { + numOfParams++; + if (nextChar == 'L') + while ((nextChar = signature[++index]) != ';'); + } + } + + // Ignore synthetic argument for member types. + int startIndex = (method.isConstructor() && isMemberType() && !isStatic()) ? 1 : 0; + int size = numOfParams - startIndex; + if (size > 0) { + parameters = new TypeBinding[size]; + index = 1; + int end = 0; // first character is always '(' so skip it + for (int i = 0; i < numOfParams; i++) { + while ((nextChar = signature[++end]) == '['); + if (nextChar == 'L') + while ((nextChar = signature[++end]) != ';'); + + if (i >= startIndex) // skip the synthetic arg if necessary + parameters[i - startIndex] = environment.getTypeFromSignature(signature, index, end); + index = end + 1; + } + } + + MethodBinding binding = null; + if (method.isConstructor()) + binding = new MethodBinding(modifiers, parameters, exceptions, this); + else + binding = new MethodBinding( + modifiers, + method.getSelector(), + environment.getTypeFromSignature(signature, index + 1, -1), // index is currently pointing at the ')' + parameters, + exceptions, + this); + return binding; +} +private void createMethods(IBinaryMethod[] iMethods) { + int total = 0; + int clinitIndex = -1; + if (iMethods != null) { + total = iMethods.length; + for (int i = total; --i >= 0;) { + char[] methodName = iMethods[i].getSelector(); + if (methodName[0] == '<' && methodName.length == 8) { // Can only match + total--; + clinitIndex = i; + break; + } + } + } + if (total == 0) { + this.methods = NoMethods; + return; + } + + this.methods = new MethodBinding[total]; + int next = 0; + for (int i = 0, length = iMethods.length; i < length; i++) + if (i != clinitIndex) + this.methods[next++] = createMethod(iMethods[i]); + modifiers |= AccUnresolved; // until methods() is sent +} +/* Answer the receiver's enclosing type... null if the receiver is a top level type. +* +* NOTE: enclosingType of a binary type is resolved when needed +*/ + +public ReferenceBinding enclosingType() { + if (enclosingType == null) + return null; + if (enclosingType instanceof UnresolvedReferenceBinding) + enclosingType = ((UnresolvedReferenceBinding) enclosingType).resolve(environment); + return enclosingType; +} +// NOTE: the type of each field of a binary type is resolved when needed + +public FieldBinding[] fields() { + for (int i = fields.length; --i >= 0;) + resolveTypeFor(fields[i]); + return fields; +} +// NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed + +public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) { + int argCount = argumentTypes.length; + nextMethod : for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (method.selector == ConstructorDeclaration.ConstantPoolName && method.parameters.length == argCount) { + resolveTypesFor(method); + TypeBinding[] toMatch = method.parameters; + for (int p = 0; p < argCount; p++) + if (toMatch[p] != argumentTypes[p]) + continue nextMethod; + return method; + } + } + return null; +} +// NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed +// searches up the hierarchy as long as no potential (but not exact) match was found. + +public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes) { + int argCount = argumentTypes.length; + int selectorLength = selector.length; + boolean foundNothing = true; + nextMethod : for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (method.selector.length == selectorLength && CharOperation.prefixEquals(method.selector, selector)) { + foundNothing = false; // inner type lookups must know that a method with this name exists + if (method.parameters.length == argCount) { + resolveTypesFor(method); + TypeBinding[] toMatch = method.parameters; + for (int p = 0; p < argCount; p++) + if (toMatch[p] != argumentTypes[p]) + continue nextMethod; + return method; + } + } + } + + if (foundNothing) { + if (isInterface()) { + if (superInterfaces.length == 1) + return superInterfaces[0].getExactMethod(selector, argumentTypes); + } else if (superclass != null) { + return superclass.getExactMethod(selector, argumentTypes); + } + } + return null; +} +// NOTE: the type of a field of a binary type is resolved when needed + +public FieldBinding getField(char[] fieldName) { + int fieldLength = fieldName.length; + for (int f = fields.length; --f >= 0;) { + char[] name = fields[f].name; + if (name.length == fieldLength && CharOperation.prefixEquals(name, fieldName)) + return resolveTypeFor(fields[f]); + } + return null; +} +// NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed + +public MethodBinding[] getMethods(char[] selector) { + int count = 0; + int lastIndex = -1; + int selectorLength = selector.length; + for (int m = 0, length = methods.length; m < length; m++) { + MethodBinding method = methods[m]; + if (method.selector.length == selectorLength && CharOperation.prefixEquals(method.selector, selector)) { + resolveTypesFor(method); + count++; + lastIndex = m; + } + } + if (count == 1) + return new MethodBinding[] {methods[lastIndex]}; + if (count > 0) { + MethodBinding[] result = new MethodBinding[count]; + count = 0; + for (int m = 0; m <= lastIndex; m++) { + MethodBinding method = methods[m]; + if (method.selector.length == selectorLength && CharOperation.prefixEquals(method.selector, selector)) + result[count++] = method; + } + return result; + } + return NoMethods; +} +// NOTE: member types of binary types are resolved when needed + +public ReferenceBinding[] memberTypes() { + for (int i = memberTypes.length; --i >= 0;) + if (memberTypes[i] instanceof UnresolvedReferenceBinding) + memberTypes[i] = ((UnresolvedReferenceBinding) memberTypes[i]).resolve(environment); + return memberTypes; +} +// NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed + +public MethodBinding[] methods() { + if ((modifiers & AccUnresolved) == 0) + return methods; + + for (int i = methods.length; --i >= 0;) + resolveTypesFor(methods[i]); + modifiers ^= AccUnresolved; + return methods; +} +private TypeBinding resolveType(TypeBinding type) { + if (type instanceof UnresolvedReferenceBinding) + return ((UnresolvedReferenceBinding) type).resolve(environment); + if (type instanceof ArrayBinding) { + ArrayBinding array = (ArrayBinding) type; + if (array.leafComponentType instanceof UnresolvedReferenceBinding) + array.leafComponentType = ((UnresolvedReferenceBinding) array.leafComponentType).resolve(environment); + } + return type; +} +private FieldBinding resolveTypeFor(FieldBinding field) { + field.type = resolveType(field.type); + return field; +} +private MethodBinding resolveTypesFor(MethodBinding method) { + if ((method.modifiers & AccUnresolved) == 0) + return method; + + if (!method.isConstructor()) + method.returnType = resolveType(method.returnType); + for (int i = method.parameters.length; --i >= 0;) + method.parameters[i] = resolveType(method.parameters[i]); + for (int i = method.thrownExceptions.length; --i >= 0;) + if (method.thrownExceptions[i] instanceof UnresolvedReferenceBinding) + method.thrownExceptions[i] = ((UnresolvedReferenceBinding) method.thrownExceptions[i]).resolve(environment); + method.modifiers ^= AccUnresolved; + return method; +} +/* Answer the receiver's superclass... null if the receiver is Object or an interface. +* +* NOTE: superclass of a binary type is resolved when needed +*/ + +public ReferenceBinding superclass() { + if (superclass == null) + return null; + if (superclass instanceof UnresolvedReferenceBinding) + superclass = ((UnresolvedReferenceBinding) superclass).resolve(environment); + return superclass; +} +// NOTE: superInterfaces of binary types are resolved when needed + +public ReferenceBinding[] superInterfaces() { + for (int i = superInterfaces.length; --i >= 0;) + if (superInterfaces[i] instanceof UnresolvedReferenceBinding) + superInterfaces[i] = ((UnresolvedReferenceBinding) superInterfaces[i]).resolve(environment); + return superInterfaces; +} +public String toString() { + String s = ""; //$NON-NLS-1$ + + if (isDeprecated()) s += "deprecated "; //$NON-NLS-1$ + if (isPublic()) s += "public "; //$NON-NLS-1$ + if (isProtected()) s += "protected "; //$NON-NLS-1$ + if (isPrivate()) s += "private "; //$NON-NLS-1$ + if (isAbstract() && isClass()) s += "abstract "; //$NON-NLS-1$ + if (isStatic() && isNestedType()) s += "static "; //$NON-NLS-1$ + if (isFinal()) s += "final "; //$NON-NLS-1$ + + s += isInterface() ? "interface " : "class "; //$NON-NLS-1$ //$NON-NLS-2$ + s += (compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED TYPE"; //$NON-NLS-1$ + + s += "\n\textends "; //$NON-NLS-1$ + s += (superclass != null) ? superclass.debugName() : "NULL TYPE"; //$NON-NLS-1$ + + if (superInterfaces != null) { + if (superInterfaces != NoSuperInterfaces) { + s += "\n\timplements : "; //$NON-NLS-1$ + for (int i = 0, length = superInterfaces.length; i < length; i++) { + if (i > 0) + s += ", "; //$NON-NLS-1$ + s += (superInterfaces[i] != null) ? superInterfaces[i].debugName() : "NULL TYPE"; //$NON-NLS-1$ + } + } + } else { + s += "NULL SUPERINTERFACES"; //$NON-NLS-1$ + } + + if (enclosingType != null) { + s += "\n\tenclosing type : "; //$NON-NLS-1$ + s += enclosingType.debugName(); + } + + if (fields != null) { + if (fields != NoFields) { + s += "\n/* fields */"; //$NON-NLS-1$ + for (int i = 0, length = fields.length; i < length; i++) + s += (fields[i] != null) ? "\n" + fields[i].toString() : "\nNULL FIELD"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } else { + s += "NULL FIELDS"; //$NON-NLS-1$ + } + + if (methods != null) { + if (methods != NoMethods) { + s += "\n/* methods */"; //$NON-NLS-1$ + for (int i = 0, length = methods.length; i < length; i++) + s += (methods[i] != null) ? "\n" + methods[i].toString() : "\nNULL METHOD"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } else { + s += "NULL METHODS"; //$NON-NLS-1$ + } + + if (memberTypes != null) { + if (memberTypes != NoMemberTypes) { + s += "\n/* members */"; //$NON-NLS-1$ + for (int i = 0, length = memberTypes.length; i < length; i++) + s += (memberTypes[i] != null) ? "\n" + memberTypes[i].toString() : "\nNULL TYPE"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } else { + s += "NULL MEMBER TYPES"; //$NON-NLS-1$ + } + + s += "\n\n\n"; //$NON-NLS-1$ + return s; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/Binding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/Binding.java new file mode 100644 index 0000000..0055540 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/Binding.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +public abstract class Binding implements BindingIds, CompilerModifiers, ProblemReasons { +/* API +* Answer the receiver's binding type from Binding.BindingID. +* +* Note: Do NOT expect this to be used very often... only in switch statements with +* more than 2 possible choices. +*/ + +public abstract int bindingType(); +/* API +* Answer true if the receiver is not a problem binding +*/ + +public final boolean isValidBinding() { + return problemId() == NoError; +} +/* API +* Answer the problem id associated with the receiver. +* NoError if the receiver is a valid binding. +*/ + +public int problemId() { + return NoError; +} +/* Answer a printable representation of the receiver. +*/ + +public abstract char[] readableName(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/BindingIds.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/BindingIds.java new file mode 100644 index 0000000..33054ec --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/BindingIds.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +public interface BindingIds { + final int FIELD = 1; + final int LOCAL = 2; + final int VARIABLE = FIELD | LOCAL; + final int TYPE = 4; + final int METHOD = 8; + final int PACKAGE = 16; + final int IMPORT = 32; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/BlockScope.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/BlockScope.java new file mode 100644 index 0000000..51f82b0 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/BlockScope.java @@ -0,0 +1,1445 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.Argument; +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream; +import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions; +import net.sourceforge.phpdt.internal.compiler.impl.Constant; +import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class BlockScope extends Scope { + + // Local variable management + public LocalVariableBinding[] locals; + public int localIndex; // position for next variable + public int startIndex; // start position in this scope - for ordering scopes vs. variables + public int offset; // for variable allocation throughout scopes + public int maxOffset; // for variable allocation throughout scopes + + // finally scopes must be shifted behind respective try scope + public BlockScope[] shiftScopes; + + public final static VariableBinding[] EmulationPathToImplicitThis = {}; + + public Scope[] subscopes = new Scope[1]; // need access from code assist + public int scopeIndex = 0; // need access from code assist + + protected BlockScope(int kind, Scope parent) { + + super(kind, parent); + } + + public BlockScope(BlockScope parent) { + + this(parent, true); + } + + public BlockScope(BlockScope parent, boolean addToParentScope) { + + this(BLOCK_SCOPE, parent); + locals = new LocalVariableBinding[5]; + if (addToParentScope) parent.addSubscope(this); + this.startIndex = parent.localIndex; + } + + public BlockScope(BlockScope parent, int variableCount) { + + this(BLOCK_SCOPE, parent); + locals = new LocalVariableBinding[variableCount]; + parent.addSubscope(this); + this.startIndex = parent.localIndex; + } + + /* Create the class scope & binding for the anonymous type. + */ + public final void addAnonymousType( + TypeDeclaration anonymousType, + ReferenceBinding superBinding) { + + ClassScope anonymousClassScope = new ClassScope(this, anonymousType); + anonymousClassScope.buildAnonymousTypeBinding( + enclosingSourceType(), + superBinding); + } + + /* Create the class scope & binding for the local type. + */ + public final void addLocalType(TypeDeclaration localType) { + + // check that the localType does not conflict with an enclosing type + ReferenceBinding type = enclosingSourceType(); + do { + if (CharOperation.equals(type.sourceName, localType.name)) { + problemReporter().hidingEnclosingType(localType); + return; + } + type = type.enclosingType(); + } while (type != null); + + // check that the localType does not conflict with another sibling local type + Scope scope = this; + do { + if (((BlockScope) scope).findLocalType(localType.name) != null) { + problemReporter().duplicateNestedType(localType); + return; + } + } while ((scope = scope.parent) instanceof BlockScope); + + ClassScope localTypeScope = new ClassScope(this, localType); + localTypeScope.buildLocalTypeBinding(enclosingSourceType()); + addSubscope(localTypeScope); + } + + /* Insert a local variable into a given scope, updating its position + * and checking there are not too many locals or arguments allocated. + */ + public final void addLocalVariable(LocalVariableBinding binding) { + + checkAndSetModifiersForVariable(binding); + + // insert local in scope + if (localIndex == locals.length) + System.arraycopy( + locals, + 0, + (locals = new LocalVariableBinding[localIndex * 2]), + 0, + localIndex); + locals[localIndex++] = binding; + + // update local variable binding + binding.declaringScope = this; + binding.id = this.outerMostMethodScope().analysisIndex++; + // share the outermost method scope analysisIndex + } + + public void addSubscope(Scope childScope) { + if (scopeIndex == subscopes.length) + System.arraycopy( + subscopes, + 0, + (subscopes = new Scope[scopeIndex * 2]), + 0, + scopeIndex); + subscopes[scopeIndex++] = childScope; + } + + /* Answer true if the receiver is suitable for assigning final blank fields. + * + * i.e. is inside an initializer, a constructor or a clinit + */ + public final boolean allowBlankFinalFieldAssignment(FieldBinding binding) { + + if (enclosingSourceType() != binding.declaringClass) + return false; + + MethodScope methodScope = methodScope(); + if (methodScope.isStatic != binding.isStatic()) + return false; + return methodScope.isInsideInitializer() // inside initializer + || ((AbstractMethodDeclaration) methodScope.referenceContext) + .isInitializationMethod(); + // inside constructor or clinit + } + String basicToString(int tab) { + String newLine = "\n"; //$NON-NLS-1$ + for (int i = tab; --i >= 0;) + newLine += "\t"; //$NON-NLS-1$ + + String s = newLine + "--- Block Scope ---"; //$NON-NLS-1$ + newLine += "\t"; //$NON-NLS-1$ + s += newLine + "locals:"; //$NON-NLS-1$ + for (int i = 0; i < localIndex; i++) + s += newLine + "\t" + locals[i].toString(); //$NON-NLS-1$ + s += newLine + "startIndex = " + startIndex; //$NON-NLS-1$ + return s; + } + + private void checkAndSetModifiersForVariable(LocalVariableBinding varBinding) { + + int modifiers = varBinding.modifiers; + if ((modifiers & AccAlternateModifierProblem) != 0 && varBinding.declaration != null){ + problemReporter().duplicateModifierForVariable(varBinding.declaration, this instanceof MethodScope); + } + int realModifiers = modifiers & AccJustFlag; + + int unexpectedModifiers = ~AccFinal; + if ((realModifiers & unexpectedModifiers) != 0 && varBinding.declaration != null){ + problemReporter().illegalModifierForVariable(varBinding.declaration, this instanceof MethodScope); + } + varBinding.modifiers = modifiers; + } + + /* Compute variable positions in scopes given an initial position offset + * ignoring unused local variables. + * + * Special treatment to have Try secret return address variables located at non + * colliding positions. Return addresses are not allocated initially, but gathered + * and allocated behind all other variables. + */ + public void computeLocalVariablePositions( + int initOffset, + CodeStream codeStream) { + + this.offset = initOffset; + this.maxOffset = initOffset; + + // local variable init + int ilocal = 0, maxLocals = 0, localsLength = locals.length; + while ((maxLocals < localsLength) && (locals[maxLocals] != null)) + maxLocals++; + boolean hasMoreVariables = maxLocals > 0; + + // scope init + int iscope = 0, maxScopes = 0, subscopesLength = subscopes.length; + while ((maxScopes < subscopesLength) && (subscopes[maxScopes] != null)) + maxScopes++; + boolean hasMoreScopes = maxScopes > 0; + + // iterate scopes and variables in parallel + while (hasMoreVariables || hasMoreScopes) { + if (hasMoreScopes + && (!hasMoreVariables || (subscopes[iscope].startIndex() <= ilocal))) { + // consider subscope first + if (subscopes[iscope] instanceof BlockScope) { + BlockScope subscope = (BlockScope) subscopes[iscope]; + int subOffset = subscope.shiftScopes == null ? this.offset : subscope.maxShiftedOffset(); + subscope.computeLocalVariablePositions(subOffset, codeStream); + if (subscope.maxOffset > this.maxOffset) + this.maxOffset = subscope.maxOffset; + } + hasMoreScopes = ++iscope < maxScopes; + } else { + // consider variable first + LocalVariableBinding local = locals[ilocal]; + + // check if variable is actually used, and may force it to be preserved + boolean generatesLocal = + (local.used && (local.constant == Constant.NotAConstant)) || local.isArgument; + if (!local.used + && (local.declaration != null) // unused (and non secret) local + && ((local.declaration.bits & AstNode.IsLocalDeclarationReachableMASK) != 0)) { // declaration is reachable + if (local.isArgument) // method argument + this.problemReporter().unusedArgument(local.declaration); + else if (!(local.declaration instanceof Argument)) // do not report unused catch arguments + this.problemReporter().unusedLocalVariable(local.declaration); + } + if (!generatesLocal) { + if (local.declaration != null + && environment().options.preserveAllLocalVariables) { + generatesLocal = true; // force it to be preserved in the generated code + local.used = true; + } + } + if (generatesLocal) { + + if (local.declaration != null) { + codeStream.record(local); + // record user local variables for attribute generation + } + // allocate variable position + local.resolvedPosition = this.offset; + + // check for too many arguments/local variables + if (local.isArgument) { + if (this.offset > 0xFF) { // no more than 255 words of arguments + this.problemReporter().noMoreAvailableSpaceForArgument(local, local.declaration); + } + } else { + if (this.offset > 0xFFFF) { // no more than 65535 words of locals + this.problemReporter().noMoreAvailableSpaceForLocal( + local, local.declaration == null ? (AstNode)this.methodScope().referenceContext : local.declaration); + } + } + + // increment offset + if ((local.type == LongBinding) || (local.type == DoubleBinding)) { + this.offset += 2; + } else { + this.offset++; + } + } else { + local.resolvedPosition = -1; // not generated + } + hasMoreVariables = ++ilocal < maxLocals; + } + } + if (this.offset > this.maxOffset) + this.maxOffset = this.offset; + } + + /* Answer true if the variable name already exists within the receiver's scope. + */ + public final LocalVariableBinding duplicateName(char[] name) { + for (int i = 0; i < localIndex; i++) + if (CharOperation.equals(name, locals[i].name)) + return locals[i]; + + if (this instanceof MethodScope) + return null; + else + return ((BlockScope) parent).duplicateName(name); + } + + /* + * Record the suitable binding denoting a synthetic field or constructor argument, + * mapping to the actual outer local variable in the scope context. + * Note that this may not need any effect, in case the outer local variable does not + * need to be emulated and can directly be used as is (using its back pointer to its + * declaring scope). + */ + public void emulateOuterAccess(LocalVariableBinding outerLocalVariable) { + + MethodScope currentMethodScope; + if ((currentMethodScope = this.methodScope()) + != outerLocalVariable.declaringScope.methodScope()) { + NestedTypeBinding currentType = (NestedTypeBinding) this.enclosingSourceType(); + + //do nothing for member types, pre emulation was performed already + if (!currentType.isLocalType()) { + return; + } + // must also add a synthetic field if we're not inside a constructor + if (!currentMethodScope.isInsideInitializerOrConstructor()) { + currentType.addSyntheticArgumentAndField(outerLocalVariable); + } else { + currentType.addSyntheticArgument(outerLocalVariable); + } + } + } + + /* + * Record the suitable binding denoting a synthetic field or constructor argument, + * mapping to a given actual enclosing instance type in the scope context. + * Skip it if the enclosingType is actually the current scope's enclosing type. + */ + + public void emulateOuterAccess( + ReferenceBinding targetEnclosingType, + boolean useDirectReference) { + + ReferenceBinding currentType = enclosingSourceType(); + if (currentType.isNestedType() + && currentType != targetEnclosingType){ + /*&& !targetEnclosingType.isSuperclassOf(currentType)*/ + + if (useDirectReference) { + // the target enclosing type is not in scope, we directly refer it + // must also add a synthetic field if we're not inside a constructor + NestedTypeBinding currentNestedType = (NestedTypeBinding) currentType; + if (methodScope().isInsideInitializerOrConstructor()) + currentNestedType.addSyntheticArgument(targetEnclosingType); + else + currentNestedType.addSyntheticArgumentAndField(targetEnclosingType); + + } else { // indirect reference sequence + int depth = 0; + + // saturate all the way up until reaching compatible enclosing type + while (currentType.isLocalType()){ + NestedTypeBinding currentNestedType = (NestedTypeBinding) currentType; + currentType = currentNestedType.enclosingType; + + if (depth == 0){ + if (methodScope().isInsideInitializerOrConstructor()) { + // must also add a synthetic field if we're not inside a constructor + currentNestedType.addSyntheticArgument(currentType); + } else { + currentNestedType.addSyntheticArgumentAndField(currentType); + } + } else if (currentNestedType == targetEnclosingType + || targetEnclosingType.isSuperclassOf(currentNestedType)) { + break; + } else { + currentNestedType.addSyntheticArgumentAndField(currentType); + } + depth++; + } + } + } + } + + /* Note that it must never produce a direct access to the targetEnclosingType, + * but instead a field sequence (this$2.this$1.this$0) so as to handle such a test case: + * + * class XX { + * void foo() { + * class A { + * class B { + * class C { + * boolean foo() { + * return (Object) A.this == (Object) B.this; + * } + * } + * } + * } + * new A().new B().new C(); + * } + * } + * where we only want to deal with ONE enclosing instance for C (could not figure out an A for C) + */ + public final ReferenceBinding findLocalType(char[] name) { + + for (int i = 0, length = scopeIndex; i < length; i++) { + if (subscopes[i] instanceof ClassScope) { + SourceTypeBinding sourceType = + ((ClassScope) subscopes[i]).referenceContext.binding; + if (CharOperation.equals(sourceType.sourceName(), name)) + return sourceType; + } + } + return null; + } + + public LocalVariableBinding findVariable(char[] variable) { + + int variableLength = variable.length; + for (int i = 0, length = locals.length; i < length; i++) { + LocalVariableBinding local = locals[i]; + if (local == null) + return null; + if (local.name.length == variableLength + && CharOperation.prefixEquals(local.name, variable)) + return local; + } + return null; + } + /* API + * flag is a mask of the following values VARIABLE (= FIELD or LOCAL), TYPE. + * Only bindings corresponding to the mask will be answered. + * + * if the VARIABLE mask is set then + * If the first name provided is a field (or local) then the field (or local) is answered + * Otherwise, package names and type names are consumed until a field is found. + * In this case, the field is answered. + * + * if the TYPE mask is set, + * package names and type names are consumed until the end of the input. + * Only if all of the input is consumed is the type answered + * + * All other conditions are errors, and a problem binding is returned. + * + * NOTE: If a problem binding is returned, senders should extract the compound name + * from the binding & not assume the problem applies to the entire compoundName. + * + * The VARIABLE mask has precedence over the TYPE mask. + * + * InvocationSite implements + * isSuperAccess(); this is used to determine if the discovered field is visible. + * setFieldIndex(int); this is used to record the number of names that were consumed. + * + * For example, getBinding({"foo","y","q", VARIABLE, site) will answer + * the binding for the field or local named "foo" (or an error binding if none exists). + * In addition, setFieldIndex(1) will be sent to the invocation site. + * If a type named "foo" exists, it will not be detected (and an error binding will be answered) + * + * IMPORTANT NOTE: This method is written under the assumption that compoundName is longer than length 1. + */ + public Binding getBinding(char[][] compoundName, int mask, InvocationSite invocationSite) { + + Binding binding = getBinding(compoundName[0], mask | TYPE | PACKAGE, invocationSite); + invocationSite.setFieldIndex(1); + if (binding instanceof VariableBinding) return binding; + compilationUnitScope().recordSimpleReference(compoundName[0]); + if (!binding.isValidBinding()) return binding; + + int length = compoundName.length; + int currentIndex = 1; + foundType : if (binding instanceof PackageBinding) { + PackageBinding packageBinding = (PackageBinding) binding; + while (currentIndex < length) { + compilationUnitScope().recordReference(packageBinding.compoundName, compoundName[currentIndex]); + binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]); + invocationSite.setFieldIndex(currentIndex); + if (binding == null) { + if (currentIndex == length) + // must be a type if its the last name, otherwise we have no idea if its a package or type + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + else + return new ProblemBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + } + if (binding instanceof ReferenceBinding) { + if (!binding.isValidBinding()) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + binding.problemId()); + if (!((ReferenceBinding) binding).canBeSeenBy(this)) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + binding, + NotVisible); + break foundType; + } + packageBinding = (PackageBinding) binding; + } + + // It is illegal to request a PACKAGE from this method. + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + } + + // know binding is now a ReferenceBinding + while (currentIndex < length) { + ReferenceBinding typeBinding = (ReferenceBinding) binding; + char[] nextName = compoundName[currentIndex++]; + invocationSite.setFieldIndex(currentIndex); + invocationSite.setActualReceiverType(typeBinding); + if ((binding = findField(typeBinding, nextName, invocationSite)) != null) { + if (!binding.isValidBinding()) + return new ProblemFieldBinding( + ((FieldBinding) binding).declaringClass, + CharOperation.subarray(compoundName, 0, currentIndex), + binding.problemId()); + break; // binding is now a field + } + if ((binding = findMemberType(nextName, typeBinding)) == null) + return new ProblemBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + typeBinding, + NotFound); + if (!binding.isValidBinding()) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + binding.problemId()); + } + + if ((mask & FIELD) != 0 && (binding instanceof FieldBinding)) { + // was looking for a field and found a field + FieldBinding field = (FieldBinding) binding; + if (!field.isStatic()) + return new ProblemFieldBinding( + field.declaringClass, + CharOperation.subarray(compoundName, 0, currentIndex), + NonStaticReferenceInStaticContext); + return binding; + } + if ((mask & TYPE) != 0 && (binding instanceof ReferenceBinding)) { + // was looking for a type and found a type + return binding; + } + + // handle the case when a field or type was asked for but we resolved the compoundName to a type or field + return new ProblemBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + } + + // Added for code assist... NOT Public API + public final Binding getBinding( + char[][] compoundName, + InvocationSite invocationSite) { + int currentIndex = 0; + int length = compoundName.length; + Binding binding = + getBinding( + compoundName[currentIndex++], + VARIABLE | TYPE | PACKAGE, + invocationSite); + if (!binding.isValidBinding()) + return binding; + + foundType : if (binding instanceof PackageBinding) { + while (currentIndex < length) { + PackageBinding packageBinding = (PackageBinding) binding; + binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]); + if (binding == null) { + if (currentIndex == length) + // must be a type if its the last name, otherwise we have no idea if its a package or type + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + else + return new ProblemBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + } + if (binding instanceof ReferenceBinding) { + if (!binding.isValidBinding()) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + binding.problemId()); + if (!((ReferenceBinding) binding).canBeSeenBy(this)) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + binding, + NotVisible); + break foundType; + } + } + return binding; + } + + foundField : if (binding instanceof ReferenceBinding) { + while (currentIndex < length) { + ReferenceBinding typeBinding = (ReferenceBinding) binding; + char[] nextName = compoundName[currentIndex++]; + if ((binding = findField(typeBinding, nextName, invocationSite)) != null) { + if (!binding.isValidBinding()) + return new ProblemFieldBinding( + ((FieldBinding) binding).declaringClass, + CharOperation.subarray(compoundName, 0, currentIndex), + binding.problemId()); + if (!((FieldBinding) binding).isStatic()) + return new ProblemFieldBinding( + ((FieldBinding) binding).declaringClass, + CharOperation.subarray(compoundName, 0, currentIndex), + NonStaticReferenceInStaticContext); + break foundField; // binding is now a field + } + if ((binding = findMemberType(nextName, typeBinding)) == null) + return new ProblemBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + typeBinding, + NotFound); + if (!binding.isValidBinding()) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + binding.problemId()); + } + return binding; + } + + VariableBinding variableBinding = (VariableBinding) binding; + while (currentIndex < length) { + TypeBinding typeBinding = variableBinding.type; + if (typeBinding == null) + return new ProblemFieldBinding( + null, + CharOperation.subarray(compoundName, 0, currentIndex + 1), + NotFound); + variableBinding = + findField(typeBinding, compoundName[currentIndex++], invocationSite); + if (variableBinding == null) + return new ProblemFieldBinding( + null, + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + if (!variableBinding.isValidBinding()) + return variableBinding; + } + return variableBinding; + } + + /* API + * + * Answer the binding that corresponds to the argument name. + * flag is a mask of the following values VARIABLE (= FIELD or LOCAL), TYPE, PACKAGE. + * Only bindings corresponding to the mask can be answered. + * + * For example, getBinding("foo", VARIABLE, site) will answer + * the binding for the field or local named "foo" (or an error binding if none exists). + * If a type named "foo" exists, it will not be detected (and an error binding will be answered) + * + * The VARIABLE mask has precedence over the TYPE mask. + * + * If the VARIABLE mask is not set, neither fields nor locals will be looked for. + * + * InvocationSite implements: + * isSuperAccess(); this is used to determine if the discovered field is visible. + * + * Limitations: cannot request FIELD independently of LOCAL, or vice versa + */ + public Binding getBinding(char[] name, int mask, InvocationSite invocationSite) { + + Binding binding = null; + FieldBinding problemField = null; + if ((mask & VARIABLE) != 0) { + if (this.kind == BLOCK_SCOPE || this.kind == METHOD_SCOPE) { + LocalVariableBinding variableBinding = findVariable(name); + // looks in this scope only + if (variableBinding != null) return variableBinding; + } + + boolean insideStaticContext = false; + boolean insideConstructorCall = false; + if (this.kind == METHOD_SCOPE) { + MethodScope methodScope = (MethodScope) this; + insideStaticContext |= methodScope.isStatic; + insideConstructorCall |= methodScope.isConstructorCall; + } + + FieldBinding foundField = null; + // can be a problem field which is answered if a valid field is not found + ProblemFieldBinding foundInsideProblem = null; + // inside Constructor call or inside static context + Scope scope = parent; + int depth = 0; + int foundDepth = 0; + ReferenceBinding foundActualReceiverType = null; + done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found + switch (scope.kind) { + case METHOD_SCOPE : + MethodScope methodScope = (MethodScope) scope; + insideStaticContext |= methodScope.isStatic; + insideConstructorCall |= methodScope.isConstructorCall; + // Fall through... could duplicate the code below to save a cast - questionable optimization + case BLOCK_SCOPE : + LocalVariableBinding variableBinding = ((BlockScope) scope).findVariable(name); + // looks in this scope only + if (variableBinding != null) { + if (foundField != null && foundField.isValidBinding()) + return new ProblemFieldBinding( + foundField.declaringClass, + name, + InheritedNameHidesEnclosingName); + if (depth > 0) + invocationSite.setDepth(depth); + return variableBinding; + } + break; + case CLASS_SCOPE : + ClassScope classScope = (ClassScope) scope; + SourceTypeBinding enclosingType = classScope.referenceContext.binding; + FieldBinding fieldBinding = + classScope.findField(enclosingType, name, invocationSite); + // Use next line instead if willing to enable protected access accross inner types + // FieldBinding fieldBinding = findField(enclosingType, name, invocationSite); + if (fieldBinding != null) { // skip it if we did not find anything + if (fieldBinding.problemId() == Ambiguous) { + if (foundField == null || foundField.problemId() == NotVisible) + // supercedes any potential InheritedNameHidesEnclosingName problem + return fieldBinding; + else + // make the user qualify the field, likely wants the first inherited field (javac generates an ambiguous error instead) + return new ProblemFieldBinding( + fieldBinding.declaringClass, + name, + InheritedNameHidesEnclosingName); + } + + ProblemFieldBinding insideProblem = null; + if (fieldBinding.isValidBinding()) { + if (!fieldBinding.isStatic()) { + if (insideConstructorCall) { + insideProblem = + new ProblemFieldBinding( + fieldBinding.declaringClass, + name, + NonStaticReferenceInConstructorInvocation); + } else if (insideStaticContext) { + insideProblem = + new ProblemFieldBinding( + fieldBinding.declaringClass, + name, + NonStaticReferenceInStaticContext); + } + } + if (enclosingType == fieldBinding.declaringClass + || environment().options.complianceLevel >= CompilerOptions.JDK1_4){ + // found a valid field in the 'immediate' scope (ie. not inherited) + // OR in 1.4 mode (inherited shadows enclosing) + if (foundField == null) { + if (depth > 0){ + invocationSite.setDepth(depth); + invocationSite.setActualReceiverType(enclosingType); + } + // return the fieldBinding if it is not declared in a superclass of the scope's binding (i.e. "inherited") + return insideProblem == null ? fieldBinding : insideProblem; + } + if (foundField.isValidBinding()) + // if a valid field was found, complain when another is found in an 'immediate' enclosing type (ie. not inherited) + if (foundField.declaringClass != fieldBinding.declaringClass) + // ie. have we found the same field - do not trust field identity yet + return new ProblemFieldBinding( + fieldBinding.declaringClass, + name, + InheritedNameHidesEnclosingName); + } + } + + if (foundField == null + || (foundField.problemId() == NotVisible + && fieldBinding.problemId() != NotVisible)) { + // only remember the fieldBinding if its the first one found or the previous one was not visible & fieldBinding is... + foundDepth = depth; + foundActualReceiverType = enclosingType; + foundInsideProblem = insideProblem; + foundField = fieldBinding; + } + } + depth++; + insideStaticContext |= enclosingType.isStatic(); + // 1EX5I8Z - accessing outer fields within a constructor call is permitted + // in order to do so, we change the flag as we exit from the type, not the method + // itself, because the class scope is used to retrieve the fields. + MethodScope enclosingMethodScope = scope.methodScope(); + insideConstructorCall = + enclosingMethodScope == null ? false : enclosingMethodScope.isConstructorCall; + break; + case COMPILATION_UNIT_SCOPE : + break done; + } + scope = scope.parent; + } + + if (foundInsideProblem != null){ + return foundInsideProblem; + } + if (foundField != null) { + if (foundField.isValidBinding()){ + if (foundDepth > 0){ + invocationSite.setDepth(foundDepth); + invocationSite.setActualReceiverType(foundActualReceiverType); + } + return foundField; + } + problemField = foundField; + } + } + + // We did not find a local or instance variable. + if ((mask & TYPE) != 0) { + if ((binding = getBaseType(name)) != null) + return binding; + binding = getTypeOrPackage(name, (mask & PACKAGE) == 0 ? TYPE : TYPE | PACKAGE); + if (binding.isValidBinding() || mask == TYPE) + return binding; + // answer the problem type binding if we are only looking for a type + } else if ((mask & PACKAGE) != 0) { + compilationUnitScope().recordSimpleReference(name); + if ((binding = environment().getTopLevelPackage(name)) != null) + return binding; + } + if (problemField != null) + return problemField; + else + return new ProblemBinding(name, enclosingSourceType(), NotFound); + } + + /* + * This retrieves the argument that maps to an enclosing instance of the suitable type, + * if not found then answers nil -- do not create one + * + * #implicitThis : the implicit this will be ok + * #((arg) this$n) : available as a constructor arg + * #((arg) this$n access$m... access$p) : available as as a constructor arg + a sequence of synthetic accessors to synthetic fields + * #((fieldDescr) this$n access#m... access$p) : available as a first synthetic field + a sequence of synthetic accessors to synthetic fields + * nil : not found + * + */ + public Object[] getCompatibleEmulationPath(ReferenceBinding targetEnclosingType) { + + MethodScope currentMethodScope = this.methodScope(); + SourceTypeBinding sourceType = currentMethodScope.enclosingSourceType(); + + // identity check + if (!currentMethodScope.isStatic + && !currentMethodScope.isConstructorCall + && (sourceType == targetEnclosingType + || targetEnclosingType.isSuperclassOf(sourceType))) { + return EmulationPathToImplicitThis; // implicit this is good enough + } + if (!sourceType.isNestedType() + || sourceType.isStatic()) { // no emulation from within non-inner types + return null; + } + boolean insideConstructor = + currentMethodScope.isInsideInitializerOrConstructor(); + // use synthetic constructor arguments if possible + if (insideConstructor) { + SyntheticArgumentBinding syntheticArg; + if ((syntheticArg = ((NestedTypeBinding) sourceType).getSyntheticArgument(targetEnclosingType, this, false)) != null) { + return new Object[] { syntheticArg }; + } + } + + // use a direct synthetic field then + if (!currentMethodScope.isStatic) { + FieldBinding syntheticField; + if ((syntheticField = sourceType.getSyntheticField(targetEnclosingType, this, false)) != null) { + return new Object[] { syntheticField }; + } + // could be reached through a sequence of enclosing instance link (nested members) + Object[] path = new Object[2]; // probably at least 2 of them + ReferenceBinding currentType = sourceType.enclosingType(); + if (insideConstructor) { + path[0] = ((NestedTypeBinding) sourceType).getSyntheticArgument((SourceTypeBinding) currentType, this, false); + } else { + path[0] = + sourceType.getSyntheticField((SourceTypeBinding) currentType, this, false); + } + if (path[0] != null) { // keep accumulating + int count = 1; + ReferenceBinding currentEnclosingType; + while ((currentEnclosingType = currentType.enclosingType()) != null) { + //done? + if (currentType == targetEnclosingType + || targetEnclosingType.isSuperclassOf(currentType)) + break; + syntheticField = ((NestedTypeBinding) currentType).getSyntheticField((SourceTypeBinding) currentEnclosingType, this, false); + if (syntheticField == null) + break; + // append inside the path + if (count == path.length) { + System.arraycopy(path, 0, (path = new Object[count + 1]), 0, count); + } + // private access emulation is necessary since synthetic field is private + path[count++] = ((SourceTypeBinding) syntheticField.declaringClass).addSyntheticMethod(syntheticField, true); + currentType = currentEnclosingType; + } + if (currentType == targetEnclosingType + || targetEnclosingType.isSuperclassOf(currentType)) { + return path; + } + } + } + return null; + } + + /* API + * + * Answer the constructor binding that corresponds to receiverType, argumentTypes. + * + * InvocationSite implements + * isSuperAccess(); this is used to determine if the discovered constructor is visible. + * + * If no visible constructor is discovered, an error binding is answered. + */ + public MethodBinding getConstructor( + ReferenceBinding receiverType, + TypeBinding[] argumentTypes, + InvocationSite invocationSite) { + + compilationUnitScope().recordTypeReference(receiverType); + compilationUnitScope().recordTypeReferences(argumentTypes); + MethodBinding methodBinding = receiverType.getExactConstructor(argumentTypes); + if (methodBinding != null) + if (methodBinding.canBeSeenBy(invocationSite, this)) + return methodBinding; + + MethodBinding[] methods = + receiverType.getMethods(ConstructorDeclaration.ConstantPoolName); + if (methods == NoMethods) + return new ProblemMethodBinding( + ConstructorDeclaration.ConstantPoolName, + argumentTypes, + NotFound); + + MethodBinding[] compatible = new MethodBinding[methods.length]; + int compatibleIndex = 0; + for (int i = 0, length = methods.length; i < length; i++) + if (areParametersAssignable(methods[i].parameters, argumentTypes)) + compatible[compatibleIndex++] = methods[i]; + if (compatibleIndex == 0) + return new ProblemMethodBinding( + ConstructorDeclaration.ConstantPoolName, + argumentTypes, + NotFound); + // need a more descriptive error... cannot convert from X to Y + + MethodBinding[] visible = new MethodBinding[compatibleIndex]; + int visibleIndex = 0; + for (int i = 0; i < compatibleIndex; i++) { + MethodBinding method = compatible[i]; + if (method.canBeSeenBy(invocationSite, this)) + visible[visibleIndex++] = method; + } + if (visibleIndex == 1) + return visible[0]; + if (visibleIndex == 0) + return new ProblemMethodBinding( + ConstructorDeclaration.ConstantPoolName, + argumentTypes, + NotVisible); + return mostSpecificClassMethodBinding(visible, visibleIndex); + } + + /* + * This retrieves the argument that maps to an enclosing instance of the suitable type, + * if not found then answers nil -- do not create one + * + * #implicitThis : the implicit this will be ok + * #((arg) this$n) : available as a constructor arg + * #((arg) this$n ... this$p) : available as as a constructor arg + a sequence of fields + * #((fieldDescr) this$n ... this$p) : available as a sequence of fields + * nil : not found + * + * Note that this algorithm should answer the shortest possible sequence when + * shortcuts are available: + * this$0 . this$0 . this$0 + * instead of + * this$2 . this$1 . this$0 . this$1 . this$0 + * thus the code generation will be more compact and runtime faster + */ + public VariableBinding[] getEmulationPath(LocalVariableBinding outerLocalVariable) { + + MethodScope currentMethodScope = this.methodScope(); + SourceTypeBinding sourceType = currentMethodScope.enclosingSourceType(); + + // identity check + if (currentMethodScope == outerLocalVariable.declaringScope.methodScope()) { + return new VariableBinding[] { outerLocalVariable }; + // implicit this is good enough + } + // use synthetic constructor arguments if possible + if (currentMethodScope.isInsideInitializerOrConstructor() + && (sourceType.isNestedType())) { + SyntheticArgumentBinding syntheticArg; + if ((syntheticArg = ((NestedTypeBinding) sourceType).getSyntheticArgument(outerLocalVariable)) != null) { + return new VariableBinding[] { syntheticArg }; + } + } + // use a synthetic field then + if (!currentMethodScope.isStatic) { + FieldBinding syntheticField; + if ((syntheticField = sourceType.getSyntheticField(outerLocalVariable)) != null) { + return new VariableBinding[] { syntheticField }; + } + } + return null; + } + + /* + * This retrieves the argument that maps to an enclosing instance of the suitable type, + * if not found then answers nil -- do not create one + * + * #implicitThis : the implicit this will be ok + * #((arg) this$n) : available as a constructor arg + * #((arg) this$n access$m... access$p) : available as as a constructor arg + a sequence of synthetic accessors to synthetic fields + * #((fieldDescr) this$n access#m... access$p) : available as a first synthetic field + a sequence of synthetic accessors to synthetic fields + * nil : not found + * + * EXACT MATCH VERSION - no type compatibility is performed + */ + public Object[] getExactEmulationPath(ReferenceBinding targetEnclosingType) { + + MethodScope currentMethodScope = this.methodScope(); + SourceTypeBinding sourceType = currentMethodScope.enclosingSourceType(); + + // identity check + if (!currentMethodScope.isStatic + && !currentMethodScope.isConstructorCall + && (sourceType == targetEnclosingType)) { + return EmulationPathToImplicitThis; // implicit this is good enough + } + if (!sourceType.isNestedType() + || sourceType.isStatic()) { // no emulation from within non-inner types + return null; + } + + boolean insideConstructor = + currentMethodScope.isInsideInitializerOrConstructor(); + // use synthetic constructor arguments if possible + if (insideConstructor) { + SyntheticArgumentBinding syntheticArg; + if ((syntheticArg = ((NestedTypeBinding) sourceType).getSyntheticArgument(targetEnclosingType, this, true)) != null) { + return new Object[] { syntheticArg }; + } + } + // use a direct synthetic field then + if (!currentMethodScope.isStatic) { + FieldBinding syntheticField; + if ((syntheticField = sourceType.getSyntheticField(targetEnclosingType, this, true)) != null) { + return new Object[] { syntheticField }; + } + // could be reached through a sequence of enclosing instance link (nested members) + Object[] path = new Object[2]; // probably at least 2 of them + ReferenceBinding currentType = sourceType.enclosingType(); + if (insideConstructor) { + path[0] = + ((NestedTypeBinding) sourceType).getSyntheticArgument((SourceTypeBinding) currentType, this, true); + } else { + path[0] = + sourceType.getSyntheticField((SourceTypeBinding) currentType, this, true); + } + if (path[0] != null) { // keep accumulating + int count = 1; + ReferenceBinding currentEnclosingType; + while ((currentEnclosingType = currentType.enclosingType()) != null) { + //done? + if (currentType == targetEnclosingType) + break; + syntheticField = + ((NestedTypeBinding) currentType).getSyntheticField( + (SourceTypeBinding) currentEnclosingType, + this, + true); + if (syntheticField == null) + break; + // append inside the path + if (count == path.length) { + System.arraycopy(path, 0, (path = new Object[count + 1]), 0, count); + } + // private access emulation is necessary since synthetic field is private + path[count++] = ((SourceTypeBinding) syntheticField.declaringClass).addSyntheticMethod(syntheticField, true); + currentType = currentEnclosingType; + } + if (currentType == targetEnclosingType) { + return path; + } + } + } + return null; + } + + /* API + * + * Answer the field binding that corresponds to fieldName. + * Start the lookup at the receiverType. + * InvocationSite implements + * isSuperAccess(); this is used to determine if the discovered field is visible. + * Only fields defined by the receiverType or its supertypes are answered; + * a field of an enclosing type will not be found using this API. + * + * If no visible field is discovered, an error binding is answered. + */ + public FieldBinding getField( + TypeBinding receiverType, + char[] fieldName, + InvocationSite invocationSite) { + + FieldBinding field = findField(receiverType, fieldName, invocationSite); + if (field == null) + return new ProblemFieldBinding( + receiverType instanceof ReferenceBinding + ? (ReferenceBinding) receiverType + : null, + fieldName, + NotFound); + else + return field; + } + + /* API + * + * Answer the method binding that corresponds to selector, argumentTypes. + * Start the lookup at the enclosing type of the receiver. + * InvocationSite implements + * isSuperAccess(); this is used to determine if the discovered method is visible. + * setDepth(int); this is used to record the depth of the discovered method + * relative to the enclosing type of the receiver. (If the method is defined + * in the enclosing type of the receiver, the depth is 0; in the next enclosing + * type, the depth is 1; and so on + * + * If no visible method is discovered, an error binding is answered. + */ + public MethodBinding getImplicitMethod( + char[] selector, + TypeBinding[] argumentTypes, + InvocationSite invocationSite) { + + boolean insideStaticContext = false; + boolean insideConstructorCall = false; + MethodBinding foundMethod = null; + ProblemMethodBinding foundFuzzyProblem = null; + // the weird method lookup case (matches method name in scope, then arg types, then visibility) + ProblemMethodBinding foundInsideProblem = null; + // inside Constructor call or inside static context + Scope scope = this; + int depth = 0; + done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found + switch (scope.kind) { + case METHOD_SCOPE : + MethodScope methodScope = (MethodScope) scope; + insideStaticContext |= methodScope.isStatic; + insideConstructorCall |= methodScope.isConstructorCall; + break; + case CLASS_SCOPE : + ClassScope classScope = (ClassScope) scope; + SourceTypeBinding receiverType = classScope.referenceContext.binding; + boolean isExactMatch = true; + // retrieve an exact visible match (if possible) + MethodBinding methodBinding = + (foundMethod == null) + ? classScope.findExactMethod( + receiverType, + selector, + argumentTypes, + invocationSite) + : classScope.findExactMethod( + receiverType, + foundMethod.selector, + foundMethod.parameters, + invocationSite); + // ? findExactMethod(receiverType, selector, argumentTypes, invocationSite) + // : findExactMethod(receiverType, foundMethod.selector, foundMethod.parameters, invocationSite); + if (methodBinding == null) { + // answers closest approximation, may not check argumentTypes or visibility + isExactMatch = false; + methodBinding = + classScope.findMethod(receiverType, selector, argumentTypes, invocationSite); + // methodBinding = findMethod(receiverType, selector, argumentTypes, invocationSite); + } + if (methodBinding != null) { // skip it if we did not find anything + if (methodBinding.problemId() == Ambiguous) { + if (foundMethod == null || foundMethod.problemId() == NotVisible) + // supercedes any potential InheritedNameHidesEnclosingName problem + return methodBinding; + else + // make the user qualify the method, likely wants the first inherited method (javac generates an ambiguous error instead) + return new ProblemMethodBinding( + selector, + argumentTypes, + InheritedNameHidesEnclosingName); + } + + ProblemMethodBinding fuzzyProblem = null; + ProblemMethodBinding insideProblem = null; + if (methodBinding.isValidBinding()) { + if (!isExactMatch) { + if (!areParametersAssignable(methodBinding.parameters, argumentTypes)) { + if (foundMethod == null || foundMethod.problemId() == NotVisible){ + // inherited mismatch is reported directly, not looking at enclosing matches + return new ProblemMethodBinding(methodBinding, selector, argumentTypes, NotFound); + } + // make the user qualify the method, likely wants the first inherited method (javac generates an ambiguous error instead) + fuzzyProblem = new ProblemMethodBinding(selector, argumentTypes, InheritedNameHidesEnclosingName); + + } else if (!methodBinding.canBeSeenBy(receiverType, invocationSite, classScope)) { + // using instead of for visibility check does grant all access to innerclass + fuzzyProblem = + new ProblemMethodBinding( + selector, + argumentTypes, + methodBinding.declaringClass, + NotVisible); + } + } + if (fuzzyProblem == null && !methodBinding.isStatic()) { + if (insideConstructorCall) { + insideProblem = + new ProblemMethodBinding( + methodBinding.selector, + methodBinding.parameters, + NonStaticReferenceInConstructorInvocation); + } else if (insideStaticContext) { + insideProblem = + new ProblemMethodBinding( + methodBinding.selector, + methodBinding.parameters, + NonStaticReferenceInStaticContext); + } + } + + if (receiverType == methodBinding.declaringClass + || (receiverType.getMethods(selector)) != NoMethods + || ((fuzzyProblem == null || fuzzyProblem.problemId() != NotVisible) && environment().options.complianceLevel >= CompilerOptions.JDK1_4)){ + // found a valid method in the 'immediate' scope (ie. not inherited) + // OR the receiverType implemented a method with the correct name + // OR in 1.4 mode (inherited visible shadows enclosing) + if (foundMethod == null) { + if (depth > 0){ + invocationSite.setDepth(depth); + invocationSite.setActualReceiverType(receiverType); + } + // return the methodBinding if it is not declared in a superclass of the scope's binding (i.e. "inherited") + if (fuzzyProblem != null) + return fuzzyProblem; + if (insideProblem != null) + return insideProblem; + return methodBinding; + } + // if a method was found, complain when another is found in an 'immediate' enclosing type (ie. not inherited) + // NOTE: Unlike fields, a non visible method hides a visible method + if (foundMethod.declaringClass != methodBinding.declaringClass) + // ie. have we found the same method - do not trust field identity yet + return new ProblemMethodBinding( + methodBinding.selector, + methodBinding.parameters, + InheritedNameHidesEnclosingName); + } + } + + if (foundMethod == null + || (foundMethod.problemId() == NotVisible + && methodBinding.problemId() != NotVisible)) { + // only remember the methodBinding if its the first one found or the previous one was not visible & methodBinding is... + // remember that private methods are visible if defined directly by an enclosing class + if (depth > 0){ + invocationSite.setDepth(depth); + invocationSite.setActualReceiverType(receiverType); + } + foundFuzzyProblem = fuzzyProblem; + foundInsideProblem = insideProblem; + if (fuzzyProblem == null) + foundMethod = methodBinding; // only keep it if no error was found + } + } + depth++; + insideStaticContext |= receiverType.isStatic(); + // 1EX5I8Z - accessing outer fields within a constructor call is permitted + // in order to do so, we change the flag as we exit from the type, not the method + // itself, because the class scope is used to retrieve the fields. + MethodScope enclosingMethodScope = scope.methodScope(); + insideConstructorCall = + enclosingMethodScope == null ? false : enclosingMethodScope.isConstructorCall; + break; + case COMPILATION_UNIT_SCOPE : + break done; + } + scope = scope.parent; + } + + if (foundFuzzyProblem != null) + return foundFuzzyProblem; + if (foundInsideProblem != null) + return foundInsideProblem; + if (foundMethod != null) + return foundMethod; + return new ProblemMethodBinding(selector, argumentTypes, NotFound); + } + + /* API + * + * Answer the method binding that corresponds to selector, argumentTypes. + * Start the lookup at the receiverType. + * InvocationSite implements + * isSuperAccess(); this is used to determine if the discovered method is visible. + * + * Only methods defined by the receiverType or its supertypes are answered; + * use getImplicitMethod() to discover methods of enclosing types. + * + * If no visible method is discovered, an error binding is answered. + */ + public MethodBinding getMethod( + TypeBinding receiverType, + char[] selector, + TypeBinding[] argumentTypes, + InvocationSite invocationSite) { + + if (receiverType.isArrayType()) + return findMethodForArray( + (ArrayBinding) receiverType, + selector, + argumentTypes, + invocationSite); + if (receiverType.isBaseType()) + return new ProblemMethodBinding(selector, argumentTypes, NotFound); + + ReferenceBinding currentType = (ReferenceBinding) receiverType; + if (!currentType.canBeSeenBy(this)) + return new ProblemMethodBinding(selector, argumentTypes, NotVisible); + // *** Need a new problem id - TypeNotVisible? + + // retrieve an exact visible match (if possible) + MethodBinding methodBinding = + findExactMethod(currentType, selector, argumentTypes, invocationSite); + if (methodBinding != null) + return methodBinding; + + // answers closest approximation, may not check argumentTypes or visibility + methodBinding = + findMethod(currentType, selector, argumentTypes, invocationSite); + if (methodBinding == null) + return new ProblemMethodBinding(selector, argumentTypes, NotFound); + if (methodBinding.isValidBinding()) { + if (!areParametersAssignable(methodBinding.parameters, argumentTypes)) + return new ProblemMethodBinding( + methodBinding, + selector, + argumentTypes, + NotFound); + if (!methodBinding.canBeSeenBy(currentType, invocationSite, this)) + return new ProblemMethodBinding( + selector, + argumentTypes, + methodBinding.declaringClass, + NotVisible); + } + return methodBinding; + } + + public int maxShiftedOffset() { + int max = -1; + if (this.shiftScopes != null){ + for (int i = 0, length = this.shiftScopes.length; i < length; i++){ + int subMaxOffset = this.shiftScopes[i].maxOffset; + if (subMaxOffset > max) max = subMaxOffset; + } + } + return max; + } + + /* Answer the problem reporter to use for raising new problems. + * + * Note that as a side-effect, this updates the current reference context + * (unit, type or method) in case the problem handler decides it is necessary + * to abort. + */ + public ProblemReporter problemReporter() { + + return outerMostMethodScope().problemReporter(); + } + + /* + * Code responsible to request some more emulation work inside the invocation type, so as to supply + * correct synthetic arguments to any allocation of the target type. + */ + public void propagateInnerEmulation( + ReferenceBinding targetType, + boolean isEnclosingInstanceSupplied, + boolean useDirectReference) { + + // perform some emulation work in case there is some and we are inside a local type only + // propage emulation of the enclosing instances + ReferenceBinding[] syntheticArgumentTypes; + if ((syntheticArgumentTypes = targetType.syntheticEnclosingInstanceTypes()) + != null) { + for (int i = 0, max = syntheticArgumentTypes.length; i < max; i++) { + ReferenceBinding syntheticArgType = syntheticArgumentTypes[i]; + // need to filter out the one that could match a supplied enclosing instance + if (!(isEnclosingInstanceSupplied + && (syntheticArgType == targetType.enclosingType()))) { + this.emulateOuterAccess(syntheticArgType, useDirectReference); + } + } + } + SyntheticArgumentBinding[] syntheticArguments; + if ((syntheticArguments = targetType.syntheticOuterLocalVariables()) != null) { + for (int i = 0, max = syntheticArguments.length; i < max; i++) { + SyntheticArgumentBinding syntheticArg = syntheticArguments[i]; + // need to filter out the one that could match a supplied enclosing instance + if (!(isEnclosingInstanceSupplied + && (syntheticArg.type == targetType.enclosingType()))) { + this.emulateOuterAccess(syntheticArg.actualOuterLocalVariable); + } + } + } + } + + /* Answer the reference type of this scope. + * + * i.e. the nearest enclosing type of this scope. + */ + public TypeDeclaration referenceType() { + + return methodScope().referenceType(); + } + + // start position in this scope - for ordering scopes vs. variables + int startIndex() { + return startIndex; + } + + public String toString() { + return toString(0); + } + + public String toString(int tab) { + + String s = basicToString(tab); + for (int i = 0; i < scopeIndex; i++) + if (subscopes[i] instanceof BlockScope) + s += ((BlockScope) subscopes[i]).toString(tab + 1) + "\n"; //$NON-NLS-1$ + return s; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ClassScope.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ClassScope.java new file mode 100644 index 0000000..9b6777f --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ClassScope.java @@ -0,0 +1,874 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.Clinit; +import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.TypeReference; +import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext; +import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; +import net.sourceforge.phpdt.internal.compiler.util.HashtableOfObject; + +public class ClassScope extends Scope { + public TypeDeclaration referenceContext; + + public ClassScope(Scope parent, TypeDeclaration context) { + super(CLASS_SCOPE, parent); + this.referenceContext = context; + } + + void buildAnonymousTypeBinding(SourceTypeBinding enclosingType, ReferenceBinding supertype) { + + LocalTypeBinding anonymousType = buildLocalType(enclosingType, enclosingType.fPackage); + + SourceTypeBinding sourceType = referenceContext.binding; + if (supertype.isInterface()) { + sourceType.superclass = getJavaLangObject(); + sourceType.superInterfaces = new ReferenceBinding[] { supertype }; + } else { + sourceType.superclass = supertype; + sourceType.superInterfaces = TypeBinding.NoSuperInterfaces; + } + connectMemberTypes(); + buildFieldsAndMethods(); + anonymousType.faultInTypesForFieldsAndMethods(); + sourceType.verifyMethods(environment().methodVerifier()); + } + + private void buildFields() { + if (referenceContext.fields == null) { + referenceContext.binding.fields = NoFields; + return; + } + // count the number of fields vs. initializers + FieldDeclaration[] fields = referenceContext.fields; + int size = fields.length; + int count = 0; + for (int i = 0; i < size; i++) + if (fields[i].isField()) + count++; + + // iterate the field declarations to create the bindings, lose all duplicates + FieldBinding[] fieldBindings = new FieldBinding[count]; + HashtableOfObject knownFieldNames = new HashtableOfObject(count); + boolean duplicate = false; + count = 0; + for (int i = 0; i < size; i++) { + FieldDeclaration field = fields[i]; + if (!field.isField()) { + if (referenceContext.binding.isInterface()) + problemReporter().interfaceCannotHaveInitializers(referenceContext.binding, field); + } else { + FieldBinding fieldBinding = new FieldBinding(field, null, referenceContext.binding); + // field's type will be resolved when needed for top level types + checkAndSetModifiersForField(fieldBinding, field); + + if (knownFieldNames.containsKey(field.name)) { + duplicate = true; + FieldBinding previousBinding = (FieldBinding) knownFieldNames.get(field.name); + if (previousBinding != null) { + for (int f = 0; f < i; f++) { + FieldDeclaration previousField = fields[f]; + if (previousField.binding == previousBinding) { + problemReporter().duplicateFieldInType(referenceContext.binding, previousField); + previousField.binding = null; + break; + } + } + } + knownFieldNames.put(field.name, null); // ensure that the duplicate field is found & removed + problemReporter().duplicateFieldInType(referenceContext.binding, field); + field.binding = null; + } else { + knownFieldNames.put(field.name, fieldBinding); + // remember that we have seen a field with this name + if (fieldBinding != null) + fieldBindings[count++] = fieldBinding; + } + } + } + // remove duplicate fields + if (duplicate) { + FieldBinding[] newFieldBindings = new FieldBinding[knownFieldNames.size() - 1]; + // we know we'll be removing at least 1 duplicate name + size = count; + count = 0; + for (int i = 0; i < size; i++) { + FieldBinding fieldBinding = fieldBindings[i]; + if (knownFieldNames.get(fieldBinding.name) != null) + newFieldBindings[count++] = fieldBinding; + } + fieldBindings = newFieldBindings; + } + + if (count != fieldBindings.length) + System.arraycopy(fieldBindings, 0, fieldBindings = new FieldBinding[count], 0, count); + for (int i = 0; i < count; i++) + fieldBindings[i].id = i; + referenceContext.binding.fields = fieldBindings; + } + + void buildFieldsAndMethods() { + buildFields(); + buildMethods(); + + SourceTypeBinding sourceType = referenceContext.binding; + if (sourceType.isMemberType() && !sourceType.isLocalType()) + ((MemberTypeBinding) sourceType).checkSyntheticArgsAndFields(); + + ReferenceBinding[] memberTypes = sourceType.memberTypes; + for (int i = 0, length = memberTypes.length; i < length; i++) + ((SourceTypeBinding) memberTypes[i]).scope.buildFieldsAndMethods(); + } + + private LocalTypeBinding buildLocalType( + SourceTypeBinding enclosingType, + PackageBinding packageBinding) { + referenceContext.scope = this; + referenceContext.staticInitializerScope = new MethodScope(this, referenceContext, true); + referenceContext.initializerScope = new MethodScope(this, referenceContext, false); + + // build the binding or the local type + LocalTypeBinding localType = new LocalTypeBinding(this, enclosingType); + referenceContext.binding = localType; + checkAndSetModifiers(); + + // Look at member types + ReferenceBinding[] memberTypeBindings = NoMemberTypes; + if (referenceContext.memberTypes != null) { + int size = referenceContext.memberTypes.length; + memberTypeBindings = new ReferenceBinding[size]; + int count = 0; + nextMember : for (int i = 0; i < size; i++) { + TypeDeclaration memberContext = referenceContext.memberTypes[i]; + if (memberContext.isInterface()) { + problemReporter().nestedClassCannotDeclareInterface(memberContext); + continue nextMember; + } + ReferenceBinding type = localType; + // check that the member does not conflict with an enclosing type + do { + if (CharOperation.equals(type.sourceName, memberContext.name)) { + problemReporter().hidingEnclosingType(memberContext); + continue nextMember; + } + type = type.enclosingType(); + } while (type != null); + // check the member type does not conflict with another sibling member type + for (int j = 0; j < i; j++) { + if (CharOperation.equals(referenceContext.memberTypes[j].name, memberContext.name)) { + problemReporter().duplicateNestedType(memberContext); + continue nextMember; + } + } + + ClassScope memberScope = new ClassScope(this, referenceContext.memberTypes[i]); + LocalTypeBinding memberBinding = memberScope.buildLocalType(localType, packageBinding); + memberBinding.setAsMemberType(); + memberTypeBindings[count++] = memberBinding; + } + if (count != size) + System.arraycopy(memberTypeBindings, 0, memberTypeBindings = new ReferenceBinding[count], 0, count); + } + localType.memberTypes = memberTypeBindings; + return localType; + } + + void buildLocalTypeBinding(SourceTypeBinding enclosingType) { + + LocalTypeBinding localType = buildLocalType(enclosingType, enclosingType.fPackage); + connectTypeHierarchy(); + buildFieldsAndMethods(); + localType.faultInTypesForFieldsAndMethods(); + + referenceContext.binding.verifyMethods(environment().methodVerifier()); + } + + private void buildMethods() { + if (referenceContext.methods == null) { + referenceContext.binding.methods = NoMethods; + return; + } + + // iterate the method declarations to create the bindings + AbstractMethodDeclaration[] methods = referenceContext.methods; + int size = methods.length; + int clinitIndex = -1; + for (int i = 0; i < size; i++) { + if (methods[i] instanceof Clinit) { + clinitIndex = i; + break; + } + } + MethodBinding[] methodBindings = new MethodBinding[clinitIndex == -1 ? size : size - 1]; + + int count = 0; + for (int i = 0; i < size; i++) { + if (i != clinitIndex) { + MethodScope scope = new MethodScope(this, methods[i], false); + MethodBinding methodBinding = scope.createMethod(methods[i]); + if (methodBinding != null) // is null if binding could not be created + methodBindings[count++] = methodBinding; + } + } + if (count != methodBindings.length) + System.arraycopy(methodBindings, 0, methodBindings = new MethodBinding[count], 0, count); + + referenceContext.binding.methods = methodBindings; + referenceContext.binding.modifiers |= AccUnresolved; // until methods() is sent + } + SourceTypeBinding buildType(SourceTypeBinding enclosingType, PackageBinding packageBinding) { + // provide the typeDeclaration with needed scopes + referenceContext.scope = this; + referenceContext.staticInitializerScope = new MethodScope(this, referenceContext, true); + referenceContext.initializerScope = new MethodScope(this, referenceContext, false); + + if (enclosingType == null) { + char[][] className = CharOperation.arrayConcat(packageBinding.compoundName, referenceContext.name); + referenceContext.binding = new SourceTypeBinding(className, packageBinding, this); + } else { + char[][] className = CharOperation.deepCopy(enclosingType.compoundName); + className[className.length - 1] = + CharOperation.concat(className[className.length - 1], referenceContext.name, '$'); + referenceContext.binding = new MemberTypeBinding(className, this, enclosingType); + } + + SourceTypeBinding sourceType = referenceContext.binding; + sourceType.fPackage.addType(sourceType); + checkAndSetModifiers(); + + // Look at member types + ReferenceBinding[] memberTypeBindings = NoMemberTypes; + if (referenceContext.memberTypes != null) { + int size = referenceContext.memberTypes.length; + memberTypeBindings = new ReferenceBinding[size]; + int count = 0; + nextMember : for (int i = 0; i < size; i++) { + TypeDeclaration memberContext = referenceContext.memberTypes[i]; + if (memberContext.isInterface() + && sourceType.isNestedType() + && sourceType.isClass() + && !sourceType.isStatic()) { + problemReporter().nestedClassCannotDeclareInterface(memberContext); + continue nextMember; + } + ReferenceBinding type = sourceType; + // check that the member does not conflict with an enclosing type + do { + if (CharOperation.equals(type.sourceName, memberContext.name)) { + problemReporter().hidingEnclosingType(memberContext); + continue nextMember; + } + type = type.enclosingType(); + } while (type != null); + // check that the member type does not conflict with another sibling member type + for (int j = 0; j < i; j++) { + if (CharOperation.equals(referenceContext.memberTypes[j].name, memberContext.name)) { + problemReporter().duplicateNestedType(memberContext); + continue nextMember; + } + } + + ClassScope memberScope = new ClassScope(this, memberContext); + memberTypeBindings[count++] = memberScope.buildType(sourceType, packageBinding); + } + if (count != size) + System.arraycopy(memberTypeBindings, 0, memberTypeBindings = new ReferenceBinding[count], 0, count); + } + sourceType.memberTypes = memberTypeBindings; + return sourceType; + } + + private void checkAndSetModifiers() { + SourceTypeBinding sourceType = referenceContext.binding; + int modifiers = sourceType.modifiers; + if ((modifiers & AccAlternateModifierProblem) != 0) + problemReporter().duplicateModifierForType(sourceType); + + ReferenceBinding enclosingType = sourceType.enclosingType(); + boolean isMemberType = sourceType.isMemberType(); + + if (isMemberType) { + // checks for member types before local types to catch local members + if (enclosingType.isStrictfp()) + modifiers |= AccStrictfp; + if (enclosingType.isDeprecated()) + modifiers |= AccDeprecatedImplicitly; + if (enclosingType.isInterface()) + modifiers |= AccPublic; + } else if (sourceType.isLocalType()) { + if (sourceType.isAnonymousType()) + modifiers |= AccFinal; + ReferenceContext refContext = methodScope().referenceContext; + if (refContext instanceof TypeDeclaration) { + ReferenceBinding type = ((TypeDeclaration) refContext).binding; + if (type.isStrictfp()) + modifiers |= AccStrictfp; + if (type.isDeprecated()) + modifiers |= AccDeprecatedImplicitly; + } else { + MethodBinding method = ((AbstractMethodDeclaration) refContext).binding; + if (method != null){ + if (method.isStrictfp()) + modifiers |= AccStrictfp; + if (method.isDeprecated()) + modifiers |= AccDeprecatedImplicitly; + } + } + } + // after this point, tests on the 16 bits reserved. + int realModifiers = modifiers & AccJustFlag; + + if ((realModifiers & AccInterface) != 0) { + // detect abnormal cases for interfaces + if (isMemberType) { + int unexpectedModifiers = + ~(AccPublic | AccPrivate | AccProtected | AccStatic | AccAbstract | AccInterface | AccStrictfp); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForMemberInterface(sourceType); + /* + } else if (sourceType.isLocalType()) { //interfaces cannot be defined inside a method + int unexpectedModifiers = ~(AccAbstract | AccInterface | AccStrictfp); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForLocalInterface(sourceType); + */ + } else { + int unexpectedModifiers = ~(AccPublic | AccAbstract | AccInterface | AccStrictfp); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForInterface(sourceType); + } + modifiers |= AccAbstract; + } else { + // detect abnormal cases for types + if (isMemberType) { // includes member types defined inside local types + int unexpectedModifiers = + ~(AccPublic | AccPrivate | AccProtected | AccStatic | AccAbstract | AccFinal | AccStrictfp); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForMemberClass(sourceType); + } else if (sourceType.isLocalType()) { + int unexpectedModifiers = ~(AccAbstract | AccFinal | AccStrictfp); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForLocalClass(sourceType); + } else { + int unexpectedModifiers = ~(AccPublic | AccAbstract | AccFinal | AccStrictfp); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForClass(sourceType); + } + + // check that Final and Abstract are not set together + if ((realModifiers & (AccFinal | AccAbstract)) == (AccFinal | AccAbstract)) + problemReporter().illegalModifierCombinationFinalAbstractForClass(sourceType); + } + + if (isMemberType) { + // test visibility modifiers inconsistency, isolate the accessors bits + if (enclosingType.isInterface()) { + if ((realModifiers & (AccProtected | AccPrivate)) != 0) { + problemReporter().illegalVisibilityModifierForInterfaceMemberType(sourceType); + + // need to keep the less restrictive + if ((realModifiers & AccProtected) != 0) + modifiers ^= AccProtected; + if ((realModifiers & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + } else { + int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate); + if ((accessorBits & (accessorBits - 1)) > 1) { + problemReporter().illegalVisibilityModifierCombinationForMemberType(sourceType); + + // need to keep the less restrictive + if ((accessorBits & AccPublic) != 0) { + if ((accessorBits & AccProtected) != 0) + modifiers ^= AccProtected; + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + if ((accessorBits & AccProtected) != 0) + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + } + + // static modifier test + if ((realModifiers & AccStatic) == 0) { + if (enclosingType.isInterface()) + modifiers |= AccStatic; + } else { + if (!enclosingType.isStatic()) + // error the enclosing type of a static field must be static or a top-level type + problemReporter().illegalStaticModifierForMemberType(sourceType); + } + } + + sourceType.modifiers = modifiers; + } + + /* This method checks the modifiers of a field. + * + * 9.3 & 8.3 + * Need to integrate the check for the final modifiers for nested types + * + * Note : A scope is accessible by : fieldBinding.declaringClass.scope + */ + private void checkAndSetModifiersForField(FieldBinding fieldBinding, FieldDeclaration fieldDecl) { + int modifiers = fieldBinding.modifiers; + if ((modifiers & AccAlternateModifierProblem) != 0) + problemReporter().duplicateModifierForField(fieldBinding.declaringClass, fieldDecl); + + if (fieldBinding.declaringClass.isInterface()) { + int expectedValue = AccPublic | AccStatic | AccFinal; + // set the modifiers + modifiers |= expectedValue; + + // and then check that they are the only ones + if ((modifiers & AccJustFlag) != expectedValue) + problemReporter().illegalModifierForInterfaceField(fieldBinding.declaringClass, fieldDecl); + fieldBinding.modifiers = modifiers; + return; + } + + // after this point, tests on the 16 bits reserved. + int realModifiers = modifiers & AccJustFlag; + int unexpectedModifiers = + ~(AccPublic | AccPrivate | AccProtected | AccFinal | AccStatic | AccTransient | AccVolatile); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForField(fieldBinding.declaringClass, fieldDecl); + + int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate); + if ((accessorBits & (accessorBits - 1)) > 1) { + problemReporter().illegalVisibilityModifierCombinationForField( + fieldBinding.declaringClass, + fieldDecl); + + // need to keep the less restrictive + if ((accessorBits & AccPublic) != 0) { + if ((accessorBits & AccProtected) != 0) + modifiers ^= AccProtected; + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + if ((accessorBits & AccProtected) != 0) + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + + if ((realModifiers & (AccFinal | AccVolatile)) == (AccFinal | AccVolatile)) + problemReporter().illegalModifierCombinationFinalVolatileForField( + fieldBinding.declaringClass, + fieldDecl); + + fieldBinding.modifiers = modifiers; + } + + private void checkForInheritedMemberTypes(SourceTypeBinding sourceType) { + // search up the hierarchy of the sourceType to see if any superType defines a member type + // when no member types are defined, tag the sourceType & each superType with the HasNoMemberTypes bit + ReferenceBinding currentType = sourceType; + ReferenceBinding[][] interfacesToVisit = null; + int lastPosition = -1; + do { + if ((currentType.tagBits & HasNoMemberTypes) != 0) + break; // already know it has no inherited member types, can stop looking up + if (currentType.memberTypes() != NoMemberTypes) + return; // has member types + ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (interfacesToVisit == null) + interfacesToVisit = new ReferenceBinding[5][]; + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, + 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], + 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } while ((currentType = currentType.superclass()) != null); + + boolean hasMembers = false; + if (interfacesToVisit != null) { + done : for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) { + ReferenceBinding anInterface = interfaces[j]; + if ((anInterface.tagBits & InterfaceVisited) == 0) { // if interface as not already been visited + anInterface.tagBits |= InterfaceVisited; + if ((anInterface.tagBits & HasNoMemberTypes) != 0) + continue; // already know it has no inherited member types + if (anInterface.memberTypes() != NoMemberTypes) { + hasMembers = true; + break done; + } + + ReferenceBinding[] itsInterfaces = anInterface.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, + 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], + 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } + } + } + + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) { + interfaces[j].tagBits &= ~InterfaceVisited; + if (!hasMembers) + interfaces[j].tagBits |= HasNoMemberTypes; + } + } + } + + if (!hasMembers) { + currentType = sourceType; + do { + currentType.tagBits |= HasNoMemberTypes; + } while ((currentType = currentType.superclass()) != null); + } + } + + private void connectMemberTypes() { + SourceTypeBinding sourceType = referenceContext.binding; + if (sourceType.memberTypes != NoMemberTypes) + for (int i = 0, size = sourceType.memberTypes.length; i < size; i++) + ((SourceTypeBinding) sourceType.memberTypes[i]).scope.connectTypeHierarchy(); + } + /* + Our current belief based on available JCK tests is: + inherited member types are visible as a potential superclass. + inherited interfaces are not visible when defining a superinterface. + + Error recovery story: + ensure the superclass is set to java.lang.Object if a problem is detected + resolving the superclass. + + Answer false if an error was reported against the sourceType. + */ + private boolean connectSuperclass() { + SourceTypeBinding sourceType = referenceContext.binding; + if (referenceContext.superclass == null) { + if (isJavaLangObject(sourceType)) + return true; + sourceType.superclass = getJavaLangObject(); + return !detectCycle(sourceType, sourceType.superclass, null); + // ensure Object is initialized if it comes from a source file + } + ReferenceBinding superclass = findSupertype(referenceContext.superclass); + if (superclass != null) { // is null if a cycle was detected cycle + if (!superclass.isValidBinding()) { + problemReporter().invalidSuperclass(sourceType, referenceContext.superclass, superclass); + } else if (superclass.isInterface()) { + problemReporter().superclassMustBeAClass(sourceType, referenceContext.superclass, superclass); + } else if (superclass.isFinal()) { + problemReporter().classExtendFinalClass(sourceType, referenceContext.superclass, superclass); + } else if (isJavaLangObject(sourceType)) { + // can only happen if Object extends another type... will never happen unless we're testing for it. + sourceType.tagBits |= HierarchyHasProblems; + sourceType.superclass = null; + return true; + } else { + // only want to reach here when no errors are reported + referenceContext.superclass.binding = superclass; + sourceType.superclass = superclass; + return true; + } + } + sourceType.tagBits |= HierarchyHasProblems; + if (!isJavaLangObject(sourceType)) { + sourceType.superclass = getJavaLangObject(); + if ((sourceType.superclass.tagBits & BeginHierarchyCheck) == 0) + detectCycle(sourceType, sourceType.superclass, null); + // ensure Object is initialized if it comes from a source file + } + return false; // reported some error against the source type + } + + /* + Our current belief based on available JCK 1.3 tests is: + inherited member types are visible as a potential superclass. + inherited interfaces are visible when defining a superinterface. + + Error recovery story: + ensure the superinterfaces contain only valid visible interfaces. + + Answer false if an error was reported against the sourceType. + */ + private boolean connectSuperInterfaces() { + SourceTypeBinding sourceType = referenceContext.binding; + sourceType.superInterfaces = NoSuperInterfaces; + if (referenceContext.superInterfaces == null) + return true; + + boolean noProblems = true; + int length = referenceContext.superInterfaces.length; + ReferenceBinding[] interfaceBindings = new ReferenceBinding[length]; + int count = 0; + nextInterface : for (int i = 0; i < length; i++) { + ReferenceBinding superInterface = findSupertype(referenceContext.superInterfaces[i]); + if (superInterface == null) { // detected cycle + noProblems = false; + continue nextInterface; + } + if (!superInterface.isValidBinding()) { + problemReporter().invalidSuperinterface( + sourceType, + referenceContext.superInterfaces[i], + superInterface); + sourceType.tagBits |= HierarchyHasProblems; + noProblems = false; + continue nextInterface; + } + // Check for a duplicate interface once the name is resolved, otherwise we may be confused (ie : a.b.I and c.d.I) + for (int k = 0; k < count; k++) { + if (interfaceBindings[k] == superInterface) { + // should this be treated as a warning? + problemReporter().duplicateSuperinterface(sourceType, referenceContext, superInterface); + continue nextInterface; + } + } + if (superInterface.isClass()) { + problemReporter().superinterfaceMustBeAnInterface(sourceType, referenceContext, superInterface); + sourceType.tagBits |= HierarchyHasProblems; + noProblems = false; + continue nextInterface; + } + referenceContext.superInterfaces[i].binding = superInterface; + // only want to reach here when no errors are reported + interfaceBindings[count++] = superInterface; + } + // hold onto all correctly resolved superinterfaces + if (count > 0) { + if (count != length) + System.arraycopy(interfaceBindings, 0, interfaceBindings = new ReferenceBinding[count], 0, count); + sourceType.superInterfaces = interfaceBindings; + } + return noProblems; + } + + void connectTypeHierarchy() { + SourceTypeBinding sourceType = referenceContext.binding; + if ((sourceType.tagBits & BeginHierarchyCheck) == 0) { + boolean noProblems = true; + sourceType.tagBits |= BeginHierarchyCheck; + if (sourceType.isClass()) + noProblems &= connectSuperclass(); + noProblems &= connectSuperInterfaces(); + sourceType.tagBits |= EndHierarchyCheck; + if (noProblems && sourceType.isHierarchyInconsistent()) + problemReporter().hierarchyHasProblems(sourceType); + } + connectMemberTypes(); + checkForInheritedMemberTypes(sourceType); + } + + private void connectTypeHierarchyWithoutMembers() { + // must ensure the imports are resolved + if (parent instanceof CompilationUnitScope) { + if (((CompilationUnitScope) parent).imports == null) + ((CompilationUnitScope) parent).checkAndSetImports(); + } else if (parent instanceof ClassScope) { + // ensure that the enclosing type has already been checked + ((ClassScope) parent).connectTypeHierarchyWithoutMembers(); + } + + // double check that the hierarchy search has not already begun... + SourceTypeBinding sourceType = referenceContext.binding; + if ((sourceType.tagBits & BeginHierarchyCheck) != 0) + return; + + boolean noProblems = true; + sourceType.tagBits |= BeginHierarchyCheck; + if (sourceType.isClass()) + noProblems &= connectSuperclass(); + noProblems &= connectSuperInterfaces(); + sourceType.tagBits |= EndHierarchyCheck; + if (noProblems && sourceType.isHierarchyInconsistent()) + problemReporter().hierarchyHasProblems(sourceType); + } + + // Answer whether a cycle was found between the sourceType & the superType + private boolean detectCycle( + SourceTypeBinding sourceType, + ReferenceBinding superType, + TypeReference reference) { + if (sourceType == superType) { + problemReporter().hierarchyCircularity(sourceType, superType, reference); + sourceType.tagBits |= HierarchyHasProblems; + return true; + } + + if (superType.isBinaryBinding()) { + // force its superclass & superinterfaces to be found... 2 possibilities exist - the source type is included in the hierarchy of: + // - a binary type... this case MUST be caught & reported here + // - another source type... this case is reported against the other source type + boolean hasCycle = false; + if (superType.superclass() != null) { + if (sourceType == superType.superclass()) { + problemReporter().hierarchyCircularity(sourceType, superType, reference); + sourceType.tagBits |= HierarchyHasProblems; + superType.tagBits |= HierarchyHasProblems; + return true; + } + hasCycle |= detectCycle(sourceType, superType.superclass(), reference); + if ((superType.superclass().tagBits & HierarchyHasProblems) != 0) { + sourceType.tagBits |= HierarchyHasProblems; + superType.tagBits |= HierarchyHasProblems; // propagate down the hierarchy + } + } + + ReferenceBinding[] itsInterfaces = superType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + for (int i = 0, length = itsInterfaces.length; i < length; i++) { + ReferenceBinding anInterface = itsInterfaces[i]; + if (sourceType == anInterface) { + problemReporter().hierarchyCircularity(sourceType, superType, reference); + sourceType.tagBits |= HierarchyHasProblems; + superType.tagBits |= HierarchyHasProblems; + return true; + } + hasCycle |= detectCycle(sourceType, anInterface, reference); + if ((anInterface.tagBits & HierarchyHasProblems) != 0) { + sourceType.tagBits |= HierarchyHasProblems; + superType.tagBits |= HierarchyHasProblems; + } + } + } + return hasCycle; + } + + if ((superType.tagBits & EndHierarchyCheck) == 0 + && (superType.tagBits & BeginHierarchyCheck) != 0) { + problemReporter().hierarchyCircularity(sourceType, superType, reference); + sourceType.tagBits |= HierarchyHasProblems; + superType.tagBits |= HierarchyHasProblems; + return true; + } + if ((superType.tagBits & BeginHierarchyCheck) == 0) + // ensure if this is a source superclass that it has already been checked + ((SourceTypeBinding) superType).scope.connectTypeHierarchyWithoutMembers(); + if ((superType.tagBits & HierarchyHasProblems) != 0) + sourceType.tagBits |= HierarchyHasProblems; + return false; + } + + private ReferenceBinding findSupertype(TypeReference typeReference) { + typeReference.aboutToResolve(this); // allows us to trap completion & selection nodes + char[][] compoundName = typeReference.getTypeName(); + compilationUnitScope().recordQualifiedReference(compoundName); + SourceTypeBinding sourceType = referenceContext.binding; + int size = compoundName.length; + int n = 1; + ReferenceBinding superType; + + // resolve the first name of the compoundName + if (CharOperation.equals(compoundName[0], sourceType.sourceName)) { + superType = sourceType; + // match against the sourceType even though nested members cannot be supertypes + } else { + Binding typeOrPackage = parent.getTypeOrPackage(compoundName[0], TYPE | PACKAGE); + if (typeOrPackage == null || !typeOrPackage.isValidBinding()) + return new ProblemReferenceBinding( + compoundName[0], + typeOrPackage == null ? NotFound : typeOrPackage.problemId()); + + boolean checkVisibility = false; + for (; n < size; n++) { + if (!(typeOrPackage instanceof PackageBinding)) + break; + PackageBinding packageBinding = (PackageBinding) typeOrPackage; + typeOrPackage = packageBinding.getTypeOrPackage(compoundName[n]); + if (typeOrPackage == null || !typeOrPackage.isValidBinding()) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, n + 1), + typeOrPackage == null ? NotFound : typeOrPackage.problemId()); + checkVisibility = true; + } + + // convert to a ReferenceBinding + if (typeOrPackage instanceof PackageBinding) // error, the compoundName is a packageName + return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, n), NotFound); + superType = (ReferenceBinding) typeOrPackage; + compilationUnitScope().recordTypeReference(superType); // to record supertypes + + if (checkVisibility + && n == size) { // if we're finished and know the final supertype then check visibility + if (!superType.canBeSeenBy(sourceType.fPackage)) + // its a toplevel type so just check package access + return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, n), superType, NotVisible); + } + } + // at this point we know we have a type but we have to look for cycles + while (true) { + // must detect cycles & force connection up the hierarchy... also handle cycles with binary types. + // must be guaranteed that the superType knows its entire hierarchy + if (detectCycle(sourceType, superType, typeReference)) + return null; // cycle error was already reported + + if (n >= size) + break; + + // retrieve the next member type + char[] typeName = compoundName[n++]; + superType = findMemberType(typeName, superType); + if (superType == null) + return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, n), NotFound); + if (!superType.isValidBinding()) { + superType.compoundName = CharOperation.subarray(compoundName, 0, n); + return superType; + } + } + return superType; + } + + /* Answer the problem reporter to use for raising new problems. + * + * Note that as a side-effect, this updates the current reference context + * (unit, type or method) in case the problem handler decides it is necessary + * to abort. + */ + public ProblemReporter problemReporter() { + MethodScope outerMethodScope; + if ((outerMethodScope = outerMostMethodScope()) == null) { + ProblemReporter problemReporter = referenceCompilationUnit().problemReporter; + problemReporter.referenceContext = referenceContext; + return problemReporter; + } else { + return outerMethodScope.problemReporter(); + } + } + + /* Answer the reference type of this scope. + * + * i.e. the nearest enclosing type of this scope. + */ + public TypeDeclaration referenceType() { + return referenceContext; + } + + public String toString() { + if (referenceContext != null) + return "--- Class Scope ---\n\n" //$NON-NLS-1$ + +referenceContext.binding.toString(); + else + return "--- Class Scope ---\n\n Binding not initialized" ; //$NON-NLS-1$ + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/CompilationUnitScope.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/CompilationUnitScope.java new file mode 100644 index 0000000..dc4f59f --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/CompilationUnitScope.java @@ -0,0 +1,508 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.ImportReference; +import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions; +import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; +import net.sourceforge.phpdt.internal.compiler.util.CompoundNameVector; +import net.sourceforge.phpdt.internal.compiler.util.HashtableOfType; +import net.sourceforge.phpdt.internal.compiler.util.ObjectVector; +import net.sourceforge.phpdt.internal.compiler.util.SimpleNameVector; + +public class CompilationUnitScope extends Scope { + public LookupEnvironment environment; + public CompilationUnitDeclaration referenceContext; + public char[][] currentPackageName; + public PackageBinding fPackage; + public ImportBinding[] imports; + + public SourceTypeBinding[] topLevelTypes; + + private CompoundNameVector qualifiedReferences; + private SimpleNameVector simpleNameReferences; + private ObjectVector referencedTypes; + +public CompilationUnitScope(CompilationUnitDeclaration unit, LookupEnvironment environment) { + super(COMPILATION_UNIT_SCOPE, null); + this.environment = environment; + this.referenceContext = unit; + unit.scope = this; + this.currentPackageName = unit.currentPackage == null ? NoCharChar : unit.currentPackage.tokens; + + if (environment.options.produceReferenceInfo) { + this.qualifiedReferences = new CompoundNameVector(); + this.simpleNameReferences = new SimpleNameVector(); + this.referencedTypes = new ObjectVector(); + } else { + this.qualifiedReferences = null; // used to test if dependencies should be recorded + this.simpleNameReferences = null; + this.referencedTypes = null; + } +} +void buildFieldsAndMethods() { + for (int i = 0, length = topLevelTypes.length; i < length; i++) + topLevelTypes[i].scope.buildFieldsAndMethods(); +} +void buildTypeBindings() { + topLevelTypes = new SourceTypeBinding[0]; // want it initialized if the package cannot be resolved + if (referenceContext.compilationResult.compilationUnit != null) { + char[][] expectedPackageName = referenceContext.compilationResult.compilationUnit.getPackageName(); + if (expectedPackageName != null && !CharOperation.equals(currentPackageName, expectedPackageName)) { + problemReporter().packageIsNotExpectedPackage(referenceContext); + currentPackageName = expectedPackageName.length == 0 ? NoCharChar : expectedPackageName; + } + } + if (currentPackageName == NoCharChar) { + if ((fPackage = environment.defaultPackage) == null) { + problemReporter().mustSpecifyPackage(referenceContext); + return; + } + } else { + if ((fPackage = environment.createPackage(currentPackageName)) == null) { + problemReporter().packageCollidesWithType(referenceContext); + return; + } + recordQualifiedReference(currentPackageName); // always dependent on your own package + } + + // Skip typeDeclarations which know of previously reported errors + TypeDeclaration[] types = referenceContext.types; + int typeLength = (types == null) ? 0 : types.length; + topLevelTypes = new SourceTypeBinding[typeLength]; + int count = 0; + nextType: for (int i = 0; i < typeLength; i++) { + TypeDeclaration typeDecl = types[i]; + ReferenceBinding typeBinding = fPackage.getType0(typeDecl.name); + recordSimpleReference(typeDecl.name); // needed to detect collision cases + if (typeBinding != null && !(typeBinding instanceof UnresolvedReferenceBinding)) { + // if a type exists, it must be a valid type - cannot be a NotFound problem type + // unless its an unresolved type which is now being defined + problemReporter().duplicateTypes(referenceContext, typeDecl); + continue nextType; + } + boolean packageExists = currentPackageName == NoCharChar + ? environment.getTopLevelPackage(typeDecl.name) != null + : (fPackage.getPackage(typeDecl.name)) != null; + if (packageExists) { + // if a package exists, it must be a valid package - cannot be a NotFound problem package + problemReporter().typeCollidesWithPackage(referenceContext, typeDecl); + continue nextType; + } + + if ((typeDecl.modifiers & AccPublic) != 0) { + char[] mainTypeName; + if ((mainTypeName = referenceContext.getMainTypeName()) != null // mainTypeName == null means that implementor of ICompilationUnit decided to return null + && !CharOperation.equals(mainTypeName, typeDecl.name)) { + problemReporter().publicClassMustMatchFileName(referenceContext, typeDecl); + continue nextType; + } + } + + ClassScope child = new ClassScope(this, typeDecl); + topLevelTypes[count++] = child.buildType(null, fPackage); + } + + // shrink topLevelTypes... only happens if an error was reported + if (count != topLevelTypes.length) + System.arraycopy(topLevelTypes, 0, topLevelTypes = new SourceTypeBinding[count], 0, count); +} +void checkAndSetImports() { + // initialize the default imports if necessary... share the default java.lang.* import + if (environment.defaultImports == null) { + Binding importBinding = environment.getTopLevelPackage(JAVA); + if (importBinding != null) + importBinding = ((PackageBinding) importBinding).getTypeOrPackage(JAVA_LANG[1]); + + // abort if java.lang cannot be found... + if (importBinding == null || !importBinding.isValidBinding()) + problemReporter().isClassPathCorrect(JAVA_LANG_OBJECT, referenceCompilationUnit()); + + environment.defaultImports = new ImportBinding[] {new ImportBinding(JAVA_LANG, true, importBinding, null)}; + } + if (referenceContext.imports == null) { + imports = environment.defaultImports; + return; + } + + // allocate the import array, add java.lang.* by default + int numberOfStatements = referenceContext.imports.length; + int numberOfImports = numberOfStatements + 1; + for (int i = 0; i < numberOfStatements; i++) { + ImportReference importReference = referenceContext.imports[i]; + if (importReference.onDemand && CharOperation.equals(JAVA_LANG, importReference.tokens)) { + numberOfImports--; + break; + } + } + ImportBinding[] resolvedImports = new ImportBinding[numberOfImports]; + resolvedImports[0] = environment.defaultImports[0]; + int index = 1; + + nextImport : for (int i = 0; i < numberOfStatements; i++) { + ImportReference importReference = referenceContext.imports[i]; + char[][] compoundName = importReference.tokens; + + // skip duplicates or imports of the current package + for (int j = 0; j < index; j++) + if (resolvedImports[j].onDemand == importReference.onDemand) + if (CharOperation.equals(compoundName, resolvedImports[j].compoundName)) + continue nextImport; + if (importReference.onDemand == true) + if (CharOperation.equals(compoundName, currentPackageName)) + continue nextImport; + + if (importReference.onDemand) { + Binding importBinding = findOnDemandImport(compoundName); + if (!importBinding.isValidBinding()) + continue nextImport; // we report all problems in faultInImports() + resolvedImports[index++] = new ImportBinding(compoundName, true, importBinding, importReference); + } else { + resolvedImports[index++] = new ImportBinding(compoundName, false, null, importReference); + } + } + + // shrink resolvedImports... only happens if an error was reported + if (resolvedImports.length > index) + System.arraycopy(resolvedImports, 0, resolvedImports = new ImportBinding[index], 0, index); + imports = resolvedImports; +} +void connectTypeHierarchy() { + for (int i = 0, length = topLevelTypes.length; i < length; i++) + topLevelTypes[i].scope.connectTypeHierarchy(); +} +void faultInImports() { + if (referenceContext.imports == null) + return; + + // collect the top level type names if a single type import exists + int numberOfStatements = referenceContext.imports.length; + HashtableOfType typesBySimpleNames = null; + for (int i = 0; i < numberOfStatements; i++) { + if (!referenceContext.imports[i].onDemand) { + typesBySimpleNames = new HashtableOfType(topLevelTypes.length + numberOfStatements); + for (int j = 0, length = topLevelTypes.length; j < length; j++) + typesBySimpleNames.put(topLevelTypes[j].sourceName, topLevelTypes[j]); + break; + } + } + + // allocate the import array, add java.lang.* by default + int numberOfImports = numberOfStatements + 1; + for (int i = 0; i < numberOfStatements; i++) { + ImportReference importReference = referenceContext.imports[i]; + if (importReference.onDemand && CharOperation.equals(JAVA_LANG, importReference.tokens)) { + numberOfImports--; + break; + } + } + ImportBinding[] resolvedImports = new ImportBinding[numberOfImports]; + resolvedImports[0] = environment.defaultImports[0]; + int index = 1; + + nextImport : for (int i = 0; i < numberOfStatements; i++) { + ImportReference importReference = referenceContext.imports[i]; + char[][] compoundName = importReference.tokens; + + // skip duplicates or imports of the current package + for (int j = 0; j < index; j++) + if (resolvedImports[j].onDemand == importReference.onDemand) + if (CharOperation.equals(compoundName, resolvedImports[j].compoundName)) { + continue nextImport; + } + if (importReference.onDemand == true) + if (CharOperation.equals(compoundName, currentPackageName)) { + continue nextImport; + } + if (importReference.onDemand) { + Binding importBinding = findOnDemandImport(compoundName); + if (!importBinding.isValidBinding()) { + problemReporter().importProblem(importReference, importBinding); + continue nextImport; + } + resolvedImports[index++] = new ImportBinding(compoundName, true, importBinding, importReference); + } else { + Binding typeBinding = findSingleTypeImport(compoundName); + if (!typeBinding.isValidBinding()) { + problemReporter().importProblem(importReference, typeBinding); + continue nextImport; + } + if (typeBinding instanceof PackageBinding) { + problemReporter().cannotImportPackage(importReference); + continue nextImport; + } + ReferenceBinding existingType = typesBySimpleNames.get(compoundName[compoundName.length - 1]); + if (existingType != null) { + // duplicate test above should have caught this case, but make sure + if (existingType == typeBinding) { + continue nextImport; + } + // either the type collides with a top level type or another imported type + for (int j = 0, length = topLevelTypes.length; j < length; j++) { + if (CharOperation.equals(topLevelTypes[j].sourceName, existingType.sourceName)) { + problemReporter().conflictingImport(importReference); + continue nextImport; + } + } + problemReporter().duplicateImport(importReference); + continue nextImport; + } + resolvedImports[index++] = new ImportBinding(compoundName, false, typeBinding, importReference); + typesBySimpleNames.put(compoundName[compoundName.length - 1], (ReferenceBinding) typeBinding); + } + } + + // shrink resolvedImports... only happens if an error was reported + if (resolvedImports.length > index) + System.arraycopy(resolvedImports, 0, resolvedImports = new ImportBinding[index], 0, index); + imports = resolvedImports; +} +public void faultInTypes() { + faultInImports(); + + for (int i = 0, length = topLevelTypes.length; i < length; i++) + topLevelTypes[i].faultInTypesForFieldsAndMethods(); +} +private Binding findOnDemandImport(char[][] compoundName) { + recordQualifiedReference(compoundName); + + Binding binding = environment.getTopLevelPackage(compoundName[0]); + int i = 1; + int length = compoundName.length; + foundNothingOrType: if (binding != null) { + PackageBinding packageBinding = (PackageBinding) binding; + while (i < length) { + binding = packageBinding.getTypeOrPackage(compoundName[i++]); + if (binding == null || !binding.isValidBinding()) { + binding = null; + break foundNothingOrType; + } + if (!(binding instanceof PackageBinding)) + break foundNothingOrType; + + packageBinding = (PackageBinding) binding; + } + return packageBinding; + } + + ReferenceBinding type; + if (binding == null) { + if (environment.defaultPackage == null + || environment.options.complianceLevel >= CompilerOptions.JDK1_4){ + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, i), + NotFound); + } + type = findType(compoundName[0], environment.defaultPackage, environment.defaultPackage); + if (type == null || !type.isValidBinding()) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, i), + NotFound); + i = 1; // reset to look for member types inside the default package type + } else { + type = (ReferenceBinding) binding; + } + + for (; i < length; i++) { + // does not look for inherited member types on purpose + if ((type = type.getMemberType(compoundName[i])) == null) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, i + 1), + NotFound); + } + if (!type.canBeSeenBy(fPackage)) + return new ProblemReferenceBinding(compoundName, type, NotVisible); + return type; +} +private Binding findSingleTypeImport(char[][] compoundName) { + if (compoundName.length == 1) { + // findType records the reference + // the name cannot be a package + if (environment.defaultPackage == null + || environment.options.complianceLevel >= CompilerOptions.JDK1_4) + return new ProblemReferenceBinding(compoundName, NotFound); + ReferenceBinding typeBinding = findType(compoundName[0], environment.defaultPackage, fPackage); + if (typeBinding == null) + return new ProblemReferenceBinding(compoundName, NotFound); + else + return typeBinding; + } + return findOnDemandImport(compoundName); +} +/* Answer the problem reporter to use for raising new problems. +* +* Note that as a side-effect, this updates the current reference context +* (unit, type or method) in case the problem handler decides it is necessary +* to abort. +*/ + +public ProblemReporter problemReporter() { + ProblemReporter problemReporter = referenceContext.problemReporter; + problemReporter.referenceContext = referenceContext; + return problemReporter; +} + +/* +What do we hold onto: + +1. when we resolve 'a.b.c', say we keep only 'a.b.c' + & when we fail to resolve 'c' in 'a.b', lets keep 'a.b.c' +THEN when we come across a new/changed/removed item named 'a.b.c', + we would find all references to 'a.b.c' +-> This approach fails because every type is resolved in every onDemand import to + detect collision cases... so the references could be 10 times bigger than necessary. + +2. when we resolve 'a.b.c', lets keep 'a.b' & 'c' + & when we fail to resolve 'c' in 'a.b', lets keep 'a.b' & 'c' +THEN when we come across a new/changed/removed item named 'a.b.c', + we would find all references to 'a.b' & 'c' +-> This approach does not have a space problem but fails to handle collision cases. + What happens if a type is added named 'a.b'? We would search for 'a' & 'b' but + would not find a match. + +3. when we resolve 'a.b.c', lets keep 'a', 'a.b' & 'a', 'b', 'c' + & when we fail to resolve 'c' in 'a.b', lets keep 'a', 'a.b' & 'a', 'b', 'c' +THEN when we come across a new/changed/removed item named 'a.b.c', + we would find all references to 'a.b' & 'c' +OR 'a.b' -> 'a' & 'b' +OR 'a' -> '' & 'a' +-> As long as each single char[] is interned, we should not have a space problem + and can handle collision cases. + +4. when we resolve 'a.b.c', lets keep 'a.b' & 'a', 'b', 'c' + & when we fail to resolve 'c' in 'a.b', lets keep 'a.b' & 'a', 'b', 'c' +THEN when we come across a new/changed/removed item named 'a.b.c', + we would find all references to 'a.b' & 'c' +OR 'a.b' -> 'a' & 'b' in the simple name collection +OR 'a' -> 'a' in the simple name collection +-> As long as each single char[] is interned, we should not have a space problem + and can handle collision cases. +*/ +void recordQualifiedReference(char[][] qualifiedName) { + if (qualifiedReferences == null) return; // not recording dependencies + + int length = qualifiedName.length; + if (length > 1) { + while (!qualifiedReferences.contains(qualifiedName)) { + qualifiedReferences.add(qualifiedName); + if (length == 2) { + recordSimpleReference(qualifiedName[0]); + recordSimpleReference(qualifiedName[1]); + return; + } + length--; + recordSimpleReference(qualifiedName[length]); + System.arraycopy(qualifiedName, 0, qualifiedName = new char[length][], 0, length); + } + } else if (length == 1) { + recordSimpleReference(qualifiedName[0]); + } +} +void recordReference(char[][] qualifiedEnclosingName, char[] simpleName) { + recordQualifiedReference(qualifiedEnclosingName); + recordSimpleReference(simpleName); +} +void recordSimpleReference(char[] simpleName) { + if (simpleNameReferences == null) return; // not recording dependencies + + if (!simpleNameReferences.contains(simpleName)) + simpleNameReferences.add(simpleName); +} +void recordTypeReference(TypeBinding type) { + if (referencedTypes == null) return; // not recording dependencies + + if (type.isArrayType()) + type = ((ArrayBinding) type).leafComponentType; + if (!type.isBaseType() && !referencedTypes.containsIdentical(type)) + referencedTypes.add(type); +} +void recordTypeReferences(TypeBinding[] types) { + if (qualifiedReferences == null) return; // not recording dependencies + if (types == null || types.length == 0) return; + + for (int i = 0, max = types.length; i < max; i++) { + // No need to record supertypes of method arguments & thrown exceptions, just the compoundName + // If a field/method is retrieved from such a type then a separate call does the job + TypeBinding type = types[i]; + if (type.isArrayType()) + type = ((ArrayBinding) type).leafComponentType; + if (!type.isBaseType()) { + ReferenceBinding actualType = (ReferenceBinding) type; + if (!actualType.isLocalType()) + recordQualifiedReference(actualType.isMemberType() + ? CharOperation.splitOn('.', actualType.readableName()) + : actualType.compoundName); + } + } +} +Binding resolveSingleTypeImport(ImportBinding importBinding) { + if (importBinding.resolvedImport == null) { + importBinding.resolvedImport = findSingleTypeImport(importBinding.compoundName); + if (!importBinding.resolvedImport.isValidBinding() || importBinding.resolvedImport instanceof PackageBinding) { + if (this.imports != null){ + ImportBinding[] newImports = new ImportBinding[imports.length - 1]; + for (int i = 0, n = 0, max = this.imports.length; i < max; i++) + if (this.imports[i] != importBinding){ + newImports[n++] = this.imports[i]; + } + this.imports = newImports; + } + return null; + } + } + return importBinding.resolvedImport; +} +public void storeDependencyInfo() { + // add the type hierarchy of each referenced type + // cannot do early since the hierarchy may not be fully resolved + for (int i = 0; i < referencedTypes.size; i++) { // grows as more types are added + ReferenceBinding type = (ReferenceBinding) referencedTypes.elementAt(i); + if (!type.isLocalType()) { + recordQualifiedReference(type.isMemberType() + ? CharOperation.splitOn('.', type.readableName()) + : type.compoundName); + ReferenceBinding enclosing = type.enclosingType(); + if (enclosing != null && !referencedTypes.containsIdentical(enclosing)) + referencedTypes.add(enclosing); // to record its supertypes + } + ReferenceBinding superclass = type.superclass(); + if (superclass != null && !referencedTypes.containsIdentical(superclass)) + referencedTypes.add(superclass); // to record its supertypes + ReferenceBinding[] interfaces = type.superInterfaces(); + if (interfaces != null && interfaces.length > 0) + for (int j = 0, length = interfaces.length; j < length; j++) + if (!referencedTypes.containsIdentical(interfaces[j])) + referencedTypes.add(interfaces[j]); // to record its supertypes + } + + int size = qualifiedReferences.size; + char[][][] qualifiedRefs = new char[size][][]; + for (int i = 0; i < size; i++) + qualifiedRefs[i] = qualifiedReferences.elementAt(i); + referenceContext.compilationResult.qualifiedReferences = qualifiedRefs; + + size = simpleNameReferences.size; + char[][] simpleRefs = new char[size][]; + for (int i = 0; i < size; i++) + simpleRefs[i] = simpleNameReferences.elementAt(i); + referenceContext.compilationResult.simpleNameReferences = simpleRefs; +} +public String toString() { + return "--- CompilationUnit Scope : " + new String(referenceContext.getFileName()); //$NON-NLS-1$ +} +public void verifyMethods(MethodVerifier verifier) { + for (int i = 0, length = topLevelTypes.length; i < length; i++) + topLevelTypes[i].verifyMethods(verifier); +} +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/CompilerModifiers.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/CompilerModifiers.java new file mode 100644 index 0000000..41aa40e --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/CompilerModifiers.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.classfmt.ClassFileConstants; + +public interface CompilerModifiers extends ClassFileConstants { // modifier constant + // those constants are depending upon ClassFileConstants (relying that classfiles only use the 16 lower bits) + final int AccDefault = 0; + final int AccJustFlag = 0xFFFF; + final int AccCatchesExceptions = 0x10000; + final int AccThrowsExceptions = 0x20000; + final int AccProblem = 0x40000; + final int AccFromClassFile = 0x80000; + final int AccIsConstantValue = 0x80000; + final int AccDefaultAbstract = 0x80000; + final int AccDeprecatedImplicitly = 0x200000; // ie. is deprecated itself or contained by a deprecated type + final int AccAlternateModifierProblem = 0x400000; + final int AccModifierProblem = 0x800000; + final int AccSemicolonBody = 0x1000000; + final int AccUnresolved = 0x2000000; + final int AccClearPrivateModifier = 0x4000000; // might be requested during private access emulation + final int AccVisibilityMASK = AccPublic | AccProtected | AccPrivate; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/FieldBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/FieldBinding.java new file mode 100644 index 0000000..bed0f21 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/FieldBinding.java @@ -0,0 +1,202 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration; +import net.sourceforge.phpdt.internal.compiler.impl.Constant; + +public class FieldBinding extends VariableBinding { + public ReferenceBinding declaringClass; +protected FieldBinding() { +} +public FieldBinding(char[] name, TypeBinding type, int modifiers, ReferenceBinding declaringClass, Constant constant) { + this.modifiers = modifiers; + this.type = type; + this.name = name; + this.declaringClass = declaringClass; + this.constant = constant; + + // propagate the deprecated modifier + if (this.declaringClass != null) + if (this.declaringClass.isViewedAsDeprecated() && !isDeprecated()) + this.modifiers |= AccDeprecatedImplicitly; +} +public FieldBinding(FieldDeclaration field, TypeBinding type, ReferenceBinding declaringClass) { + this(field.name, type, field.modifiers, declaringClass, null); + + field.binding = this; +} +// special API used to change field declaring class for runtime visibility check +public FieldBinding(FieldBinding initialFieldBinding, ReferenceBinding declaringClass) { + this.modifiers = initialFieldBinding.modifiers; + this.type = initialFieldBinding.type; + this.name = initialFieldBinding.name; + this.declaringClass = declaringClass; + this.constant = initialFieldBinding.constant; + this.id = initialFieldBinding.id; +} +/* API +* Answer the receiver's binding type from Binding.BindingID. +*/ + +public final int bindingType() { + return FIELD; +} +/* Answer true if the receiver is visible to the type provided by the scope. +* InvocationSite implements isSuperAccess() to provide additional information +* if the receiver is protected. +* +* NOTE: Cannot invoke this method with a compilation unit scope. +*/ + +public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invocationSite, Scope scope) { + if (isPublic()) return true; + + SourceTypeBinding invocationType = scope.enclosingSourceType(); + if (invocationType == declaringClass && invocationType == receiverType) return true; + + if (isProtected()) { + // answer true if the invocationType is the declaringClass or they are in the same package + // OR the invocationType is a subclass of the declaringClass + // AND the receiverType is the invocationType or its subclass + // OR the method is a static method accessed directly through a type + // OR previous assertions are true for one of the enclosing type + if (invocationType == declaringClass) return true; + if (invocationType.fPackage == declaringClass.fPackage) return true; + + ReferenceBinding currentType = invocationType; + int depth = 0; + do { + if (declaringClass.isSuperclassOf(currentType)) { + if (invocationSite.isSuperAccess()){ + return true; + } + // receiverType can be an array binding in one case... see if you can change it + if (receiverType instanceof ArrayBinding){ + return false; + } + if (isStatic()){ + return true; // see 1FMEPDL - return invocationSite.isTypeAccess(); + } + if (currentType == receiverType || currentType.isSuperclassOf((ReferenceBinding) receiverType)){ + if (depth > 0) invocationSite.setDepth(depth); + return true; + } + } + depth++; + currentType = currentType.enclosingType(); + } while (currentType != null); + return false; + } + + if (isPrivate()) { + // answer true if the receiverType is the declaringClass + // AND the invocationType and the declaringClass have a common enclosingType + if (receiverType != declaringClass) return false; + + if (invocationType != declaringClass) { + ReferenceBinding outerInvocationType = invocationType; + ReferenceBinding temp = outerInvocationType.enclosingType(); + while (temp != null) { + outerInvocationType = temp; + temp = temp.enclosingType(); + } + + ReferenceBinding outerDeclaringClass = declaringClass; + temp = outerDeclaringClass.enclosingType(); + while (temp != null) { + outerDeclaringClass = temp; + temp = temp.enclosingType(); + } + if (outerInvocationType != outerDeclaringClass) return false; + } + return true; + } + + // isDefault() + if (invocationType.fPackage != declaringClass.fPackage) return false; + + // receiverType can be an array binding in one case... see if you can change it + if (receiverType instanceof ArrayBinding) + return false; + ReferenceBinding type = (ReferenceBinding) receiverType; + PackageBinding declaringPackage = declaringClass.fPackage; + do { + if (declaringClass == type) return true; + if (declaringPackage != type.fPackage) return false; + } while ((type = type.superclass()) != null); + return false; +} +public final int getAccessFlags() { + return modifiers & AccJustFlag; +} +/* Answer true if the receiver has default visibility +*/ + +public final boolean isDefault() { + return !isPublic() && !isProtected() && !isPrivate(); +} +/* Answer true if the receiver is a deprecated field +*/ + +public final boolean isDeprecated() { + return (modifiers & AccDeprecated) != 0; +} +/* Answer true if the receiver has private visibility +*/ + +public final boolean isPrivate() { + return (modifiers & AccPrivate) != 0; +} +/* Answer true if the receiver has protected visibility +*/ + +public final boolean isProtected() { + return (modifiers & AccProtected) != 0; +} +/* Answer true if the receiver has public visibility +*/ + +public final boolean isPublic() { + return (modifiers & AccPublic) != 0; +} +/* Answer true if the receiver is a static field +*/ + +public final boolean isStatic() { + return (modifiers & AccStatic) != 0; +} +/* Answer true if the receiver is not defined in the source of the declaringClass +*/ + +public final boolean isSynthetic() { + return (modifiers & AccSynthetic) != 0; +} +/* Answer true if the receiver is a transient field +*/ + +public final boolean isTransient() { + return (modifiers & AccTransient) != 0; +} +/* Answer true if the receiver's declaring type is deprecated (or any of its enclosing types) +*/ + +public final boolean isViewedAsDeprecated() { + return (modifiers & AccDeprecated) != 0 || + (modifiers & AccDeprecatedImplicitly) != 0; +} +/* Answer true if the receiver is a volatile field +*/ + +public final boolean isVolatile() { + return (modifiers & AccVolatile) != 0; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ImportBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ImportBinding.java new file mode 100644 index 0000000..1727234 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ImportBinding.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.ast.ImportReference; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class ImportBinding extends Binding { + public char[][] compoundName; + public boolean onDemand; + public ImportReference reference; + + Binding resolvedImport; // must ensure the import is resolved + +public ImportBinding(char[][] compoundName, boolean isOnDemand, Binding binding, ImportReference reference) { + this.compoundName = compoundName; + this.onDemand = isOnDemand; + this.resolvedImport = binding; + this.reference = reference; +} +/* API +* Answer the receiver's binding type from Binding.BindingID. +*/ + +public final int bindingType() { + return IMPORT; +} +public char[] readableName() { + if (onDemand) + return CharOperation.concat(CharOperation.concatWith(compoundName, '.'), ".*".toCharArray()); //$NON-NLS-1$ + else + return CharOperation.concatWith(compoundName, '.'); +} +public String toString() { + return "import : " + new String(readableName()); //$NON-NLS-1$ +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/InnerEmulationDependency.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/InnerEmulationDependency.java new file mode 100644 index 0000000..a07f8ff --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/InnerEmulationDependency.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +public class InnerEmulationDependency{ + public BlockScope scope; + public boolean wasEnclosingInstanceSupplied; + public boolean useDirectAccess; + +public InnerEmulationDependency(BlockScope scope, boolean wasEnclosingInstanceSupplied, boolean useDirectAccess) { + this.scope = scope; + this.wasEnclosingInstanceSupplied = wasEnclosingInstanceSupplied; + this.useDirectAccess = useDirectAccess; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/InvocationSite.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/InvocationSite.java new file mode 100644 index 0000000..5caab05 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/InvocationSite.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +public interface InvocationSite { + boolean isSuperAccess(); + boolean isTypeAccess(); + void setDepth(int depth); + void setFieldIndex(int depth); + + // in case the receiver type does not match the actual receiver type + // e.g. pkg.Type.C (receiver type of C is type of source context, + // but actual receiver type is pkg.Type) + // e.g2. in presence of implicit access to enclosing type + void setActualReceiverType(ReferenceBinding receiverType); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/LocalTypeBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/LocalTypeBinding.java new file mode 100644 index 0000000..681d714 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/LocalTypeBinding.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.ast.AnonymousLocalTypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; +import net.sourceforge.phpdt.internal.compiler.util.Util; + +public final class LocalTypeBinding extends NestedTypeBinding { + final static char[] LocalTypePrefix = { '$', 'L', 'o', 'c', 'a', 'l', '$' }; + + private InnerEmulationDependency[] dependents; +public LocalTypeBinding(ClassScope scope, SourceTypeBinding enclosingType) { + super( + new char[][] {CharOperation.concat(LocalTypePrefix, scope.referenceContext.name)}, + scope, + enclosingType); + + if (this.sourceName == AnonymousLocalTypeDeclaration.ANONYMOUS_EMPTY_NAME) + this.tagBits |= AnonymousTypeMask; + else + this.tagBits |= LocalTypeMask; +} +/* Record a dependency onto a source target type which may be altered +* by the end of the innerclass emulation. Later on, we will revisit +* all its dependents so as to update them (see updateInnerEmulationDependents()). +*/ + +public void addInnerEmulationDependent(BlockScope scope, boolean wasEnclosingInstanceSupplied, boolean useDirectAccess) { + int index; + if (dependents == null) { + index = 0; + dependents = new InnerEmulationDependency[1]; + } else { + index = dependents.length; + for (int i = 0; i < index; i++) + if (dependents[i].scope == scope) + return; // already stored + System.arraycopy(dependents, 0, (dependents = new InnerEmulationDependency[index + 1]), 0, index); + } + dependents[index] = new InnerEmulationDependency(scope, wasEnclosingInstanceSupplied, useDirectAccess); + // System.out.println("Adding dependency: "+ new String(scope.enclosingType().readableName()) + " --> " + new String(this.readableName())); +} +/* Answer the receiver's constant pool name. +* +* NOTE: This method should only be used during/after code gen. +*/ + +public char[] constantPoolName() /* java/lang/Object */ { + return constantPoolName; +} +public void constantPoolName(char[] computedConstantPoolName) /* java/lang/Object */ { + this.constantPoolName = computedConstantPoolName; +} +public char[] readableName() { + if (isAnonymousType()) { + if (superInterfaces == NoSuperInterfaces) + return ("<"+Util.bind("binding.subclass",new String(superclass.readableName())) + ">").toCharArray(); //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-1$ + else + return ("<"+Util.bind("binding.implementation",new String(superInterfaces[0].readableName())) + ">").toCharArray(); //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-1$ + } else if (isMemberType()) { + return CharOperation.concat(enclosingType().readableName(), sourceName, '.'); + } else { + return sourceName; + } +} +// Record that the type is a local member type + +public void setAsMemberType() { + tagBits |= MemberTypeMask; +} +public char[] sourceName() { + if (isAnonymousType()) + return readableName(); + else + return sourceName; +} +public String toString() { + if (isAnonymousType()) + return "Anonymous type : " + super.toString(); //$NON-NLS-1$ + if (isMemberType()) + return "Local member type : " + new String(sourceName()) + " " + super.toString(); //$NON-NLS-2$ //$NON-NLS-1$ + return "Local type : " + new String(sourceName()) + " " + super.toString(); //$NON-NLS-2$ //$NON-NLS-1$ +} +/* Trigger the dependency mechanism forcing the innerclass emulation +* to be propagated to all dependent source types. +*/ + +public void updateInnerEmulationDependents() { + if (dependents != null) { + for (int i = 0; i < dependents.length; i++) { + InnerEmulationDependency dependency = dependents[i]; + // System.out.println("Updating " + new String(this.readableName()) + " --> " + new String(dependency.scope.enclosingType().readableName())); + dependency.scope.propagateInnerEmulation(this, dependency.wasEnclosingInstanceSupplied, dependency.useDirectAccess); + } + } +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/LocalVariableBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/LocalVariableBinding.java new file mode 100644 index 0000000..0d454fb --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/LocalVariableBinding.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.ast.LocalDeclaration; +import net.sourceforge.phpdt.internal.compiler.impl.Constant; + +public class LocalVariableBinding extends VariableBinding { + public boolean isArgument; + + public int resolvedPosition; // for code generation (position in method context) + public boolean used; // for flow analysis + public BlockScope declaringScope; // back-pointer to its declaring scope + public LocalDeclaration declaration; // for source-positions + + public int[] initializationPCs; + public int initializationCount = 0; + +// for synthetic local variables +public LocalVariableBinding(char[] name, TypeBinding type, int modifiers, boolean isArgument) { + this.name = name; + this.type = type; + this.modifiers = modifiers; + if (this.isArgument = isArgument) + this.constant = Constant.NotAConstant; +} + +// regular local variable or argument +public LocalVariableBinding(LocalDeclaration declaration, TypeBinding type, int modifiers, boolean isArgument) { + this(declaration.name, type, modifiers, isArgument); + this.declaration = declaration; +} +/* API +* Answer the receiver's binding type from Binding.BindingID. +*/ + +public final int bindingType() { + return LOCAL; +} +// Answer whether the variable binding is a secret variable added for code gen purposes + +public boolean isSecret() { + return declaration == null && !isArgument; +} +public void recordInitializationEndPC(int pc) { + if (initializationPCs[((initializationCount - 1) << 1) + 1] == -1) + initializationPCs[((initializationCount - 1) << 1) + 1] = pc; +} +public void recordInitializationStartPC(int pc) { + if (initializationPCs == null) + return; + // optimize cases where reopening a contiguous interval + if ((initializationCount > 0) && (initializationPCs[ ((initializationCount - 1) << 1) + 1] == pc)) { + initializationPCs[ ((initializationCount - 1) << 1) + 1] = -1; // reuse previous interval (its range will be augmented) + } else { + int index = initializationCount << 1; + if (index == initializationPCs.length) { + System.arraycopy(initializationPCs, 0, (initializationPCs = new int[initializationCount << 2]), 0, index); + } + initializationPCs[index] = pc; + initializationPCs[index + 1] = -1; + initializationCount++; + } +} +public String toString() { + String s = super.toString(); + if (!used) + s += "[pos: unused]"; //$NON-NLS-1$ + else + s += "[pos: " + String.valueOf(resolvedPosition) + "]"; //$NON-NLS-2$ //$NON-NLS-1$ + s += "[id:" + String.valueOf(id) + "]"; //$NON-NLS-2$ //$NON-NLS-1$ + if (initializationCount > 0) { + s += "[pc: "; //$NON-NLS-1$ + for (int i = 0; i < initializationCount; i++) { + if (i > 0) + s += ", "; //$NON-NLS-1$ + s += String.valueOf(initializationPCs[i << 1]) + "-" + ((initializationPCs[(i << 1) + 1] == -1) ? "?" : String.valueOf(initializationPCs[(i<< 1) + 1])); //$NON-NLS-2$ //$NON-NLS-1$ + } + s += "]"; //$NON-NLS-1$ + } + return s; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/LookupEnvironment.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/LookupEnvironment.java new file mode 100644 index 0000000..781189b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/LookupEnvironment.java @@ -0,0 +1,580 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration; +import net.sourceforge.phpdt.internal.compiler.env.IBinaryType; +import net.sourceforge.phpdt.internal.compiler.env.INameEnvironment; +import net.sourceforge.phpdt.internal.compiler.env.NameEnvironmentAnswer; +import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions; +import net.sourceforge.phpdt.internal.compiler.impl.ITypeRequestor; +import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; +import net.sourceforge.phpdt.internal.compiler.util.HashtableOfPackage; +import net.sourceforge.phpdt.internal.compiler.util.Util; + +public class LookupEnvironment implements BaseTypes, ProblemReasons, TypeConstants { + public CompilerOptions options; + public ProblemReporter problemReporter; + public ITypeRequestor typeRequestor; + + PackageBinding defaultPackage; + ImportBinding[] defaultImports; + HashtableOfPackage knownPackages; + static final ProblemPackageBinding theNotFoundPackage = new ProblemPackageBinding(new char[0], NotFound); + static final ProblemReferenceBinding theNotFoundType = new ProblemReferenceBinding(new char[0], NotFound); + + private INameEnvironment nameEnvironment; + private MethodVerifier verifier; + private ArrayBinding[][] uniqueArrayBindings; + + private CompilationUnitDeclaration[] units = new CompilationUnitDeclaration[4]; + private int lastUnitIndex = -1; + private int lastCompletedUnitIndex = -1; + + // indicate in which step on the compilation we are. + // step 1 : build the reference binding + // step 2 : conect the hierarchy (connect bindings) + // step 3 : build fields and method bindings. + private int stepCompleted; + final static int BUILD_TYPE_HIERARCHY = 1; + final static int CHECK_AND_SET_IMPORTS = 2; + final static int CONNECT_TYPE_HIERARCHY = 3; + final static int BUILD_FIELDS_AND_METHODS = 4; +public LookupEnvironment(ITypeRequestor typeRequestor, CompilerOptions options, ProblemReporter problemReporter, INameEnvironment nameEnvironment) { + this.typeRequestor = typeRequestor; + this.options = options; + this.problemReporter = problemReporter; + this.defaultPackage = new PackageBinding(this); // assume the default package always exists + this.defaultImports = null; + this.nameEnvironment = nameEnvironment; + this.knownPackages = new HashtableOfPackage(); + this.uniqueArrayBindings = new ArrayBinding[5][]; + this.uniqueArrayBindings[0] = new ArrayBinding[50]; // start off the most common 1 dimension array @ 50 +} +/* Ask the oracle for a type which corresponds to the compoundName. +* Answer null if the name cannot be found. +*/ + +public ReferenceBinding askForType(char[][] compoundName) { + NameEnvironmentAnswer answer = nameEnvironment.findType(compoundName); + if (answer == null) + return null; + + if (answer.isBinaryType()) + // the type was found as a .class file + typeRequestor.accept(answer.getBinaryType(), computePackageFrom(compoundName)); + else if (answer.isCompilationUnit()) + // the type was found as a .java file, try to build it then search the cache + typeRequestor.accept(answer.getCompilationUnit()); + else if (answer.isSourceType()) + // the type was found as a source model + typeRequestor.accept(answer.getSourceTypes(), computePackageFrom(compoundName)); + + return getCachedType(compoundName); +} +/* Ask the oracle for a type named name in the packageBinding. +* Answer null if the name cannot be found. +*/ + +ReferenceBinding askForType(PackageBinding packageBinding, char[] name) { + if (packageBinding == null) { + if (defaultPackage == null) + return null; + packageBinding = defaultPackage; + } + NameEnvironmentAnswer answer = nameEnvironment.findType(name, packageBinding.compoundName); + if (answer == null) + return null; + + if (answer.isBinaryType()) + // the type was found as a .class file + typeRequestor.accept(answer.getBinaryType(), packageBinding); + else if (answer.isCompilationUnit()) + // the type was found as a .java file, try to build it then search the cache + typeRequestor.accept(answer.getCompilationUnit()); + else if (answer.isSourceType()) + // the type was found as a source model + typeRequestor.accept(answer.getSourceTypes(), packageBinding); + + return packageBinding.getType0(name); +} +/* Create the initial type bindings for the compilation unit. +* +* See completeTypeBindings() for a description of the remaining steps +* +* NOTE: This method can be called multiple times as additional source files are needed +*/ + +public void buildTypeBindings(CompilationUnitDeclaration unit) { + CompilationUnitScope scope = new CompilationUnitScope(unit, this); + scope.buildTypeBindings(); + + int unitsLength = units.length; + if (++lastUnitIndex >= unitsLength) + System.arraycopy(units, 0, units = new CompilationUnitDeclaration[2 * unitsLength], 0, unitsLength); + units[lastUnitIndex] = unit; +} +/* Cache the binary type since we know it is needed during this compile. +* +* Answer the created BinaryTypeBinding or null if the type is already in the cache. +*/ + +public BinaryTypeBinding cacheBinaryType(IBinaryType binaryType) { + return cacheBinaryType(binaryType, true); +} +/* Cache the binary type since we know it is needed during this compile. +* +* Answer the created BinaryTypeBinding or null if the type is already in the cache. +*/ + +public BinaryTypeBinding cacheBinaryType(IBinaryType binaryType, boolean needFieldsAndMethods) { + char[][] compoundName = CharOperation.splitOn('/', binaryType.getName()); + ReferenceBinding existingType = getCachedType(compoundName); + + if (existingType == null || existingType instanceof UnresolvedReferenceBinding) + // only add the binary type if its not already in the cache + return createBinaryTypeFrom(binaryType, computePackageFrom(compoundName), needFieldsAndMethods); + return null; // the type already exists & can be retrieved from the cache +} +/* +* 1. Connect the type hierarchy for the type bindings created for parsedUnits. +* 2. Create the field bindings +* 3. Create the method bindings +*/ + +/* We know each known compilationUnit is free of errors at this point... +* +* Each step will create additional bindings unless a problem is detected, in which +* case either the faulty import/superinterface/field/method will be skipped or a +* suitable replacement will be substituted (such as Object for a missing superclass) +*/ + +public void completeTypeBindings() { + stepCompleted = BUILD_TYPE_HIERARCHY; + + for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) { + units[i].scope.checkAndSetImports(); + } + stepCompleted = CHECK_AND_SET_IMPORTS; + + for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) { + units[i].scope.connectTypeHierarchy(); + } + stepCompleted = CONNECT_TYPE_HIERARCHY; + + for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) { + units[i].scope.buildFieldsAndMethods(); + units[i] = null; // release unnecessary reference to the parsed unit + } + stepCompleted = BUILD_FIELDS_AND_METHODS; + lastCompletedUnitIndex = lastUnitIndex; +} +/* +* 1. Connect the type hierarchy for the type bindings created for parsedUnits. +* 2. Create the field bindings +* 3. Create the method bindings +*/ + +/* +* Each step will create additional bindings unless a problem is detected, in which +* case either the faulty import/superinterface/field/method will be skipped or a +* suitable replacement will be substituted (such as Object for a missing superclass) +*/ + +public void completeTypeBindings(CompilationUnitDeclaration parsedUnit) { + if (stepCompleted == BUILD_FIELDS_AND_METHODS) { + // This can only happen because the original set of units are completely built and + // are now being processed, so we want to treat all the additional units as a group + // until they too are completely processed. + completeTypeBindings(); + } else { + if (parsedUnit.scope == null) return; // parsing errors were too severe + + if (stepCompleted >= CHECK_AND_SET_IMPORTS) + parsedUnit.scope.checkAndSetImports(); + + if (stepCompleted >= CONNECT_TYPE_HIERARCHY) + parsedUnit.scope.connectTypeHierarchy(); + } +} +/* +* Used by other compiler tools which do not start by calling completeTypeBindings(). +* +* 1. Connect the type hierarchy for the type bindings created for parsedUnits. +* 2. Create the field bindings +* 3. Create the method bindings +*/ + +public void completeTypeBindings(CompilationUnitDeclaration parsedUnit, boolean buildFieldsAndMethods) { + if (parsedUnit.scope == null) return; // parsing errors were too severe + + parsedUnit.scope.checkAndSetImports(); + parsedUnit.scope.connectTypeHierarchy(); + + if (buildFieldsAndMethods) + parsedUnit.scope.buildFieldsAndMethods(); +} +private PackageBinding computePackageFrom(char[][] constantPoolName) { + if (constantPoolName.length == 1) + return defaultPackage; + + PackageBinding packageBinding = getPackage0(constantPoolName[0]); + if (packageBinding == null || packageBinding == theNotFoundPackage) { + packageBinding = new PackageBinding(constantPoolName[0], this); + knownPackages.put(constantPoolName[0], packageBinding); + } + + for (int i = 1, length = constantPoolName.length - 1; i < length; i++) { + PackageBinding parent = packageBinding; + if ((packageBinding = parent.getPackage0(constantPoolName[i])) == null || packageBinding == theNotFoundPackage) { + packageBinding = new PackageBinding(CharOperation.subarray(constantPoolName, 0, i + 1), parent, this); + parent.addPackage(packageBinding); + } + } + return packageBinding; +} +/* Used to guarantee array type identity. +*/ + +ArrayBinding createArrayType(TypeBinding type, int dimensionCount) { + // find the array binding cache for this dimension + int dimIndex = dimensionCount - 1; + int length = uniqueArrayBindings.length; + ArrayBinding[] arrayBindings; + if (dimIndex < length) { + if ((arrayBindings = uniqueArrayBindings[dimIndex]) == null) + uniqueArrayBindings[dimIndex] = arrayBindings = new ArrayBinding[10]; + } else { + System.arraycopy( + uniqueArrayBindings, 0, + uniqueArrayBindings = new ArrayBinding[dimensionCount][], 0, + length); + uniqueArrayBindings[dimIndex] = arrayBindings = new ArrayBinding[10]; + } + + // find the cached array binding for this leaf component type (if any) + int index = -1; + length = arrayBindings.length; + while (++index < length) { + ArrayBinding currentBinding = arrayBindings[index]; + if (currentBinding == null) // no matching array, but space left + return arrayBindings[index] = new ArrayBinding(type, dimensionCount); + if (currentBinding.leafComponentType == type) + return currentBinding; + } + + // no matching array, no space left + System.arraycopy( + arrayBindings, 0, + (arrayBindings = new ArrayBinding[length * 2]), 0, + length); + uniqueArrayBindings[dimIndex] = arrayBindings; + return arrayBindings[length] = new ArrayBinding(type, dimensionCount); +} +public BinaryTypeBinding createBinaryTypeFrom(IBinaryType binaryType, PackageBinding packageBinding) { + return createBinaryTypeFrom(binaryType, packageBinding, true); +} +public BinaryTypeBinding createBinaryTypeFrom(IBinaryType binaryType, PackageBinding packageBinding, boolean needFieldsAndMethods) { + BinaryTypeBinding binaryBinding = new BinaryTypeBinding(packageBinding, binaryType, this); + + // resolve any array bindings which reference the unresolvedType + ReferenceBinding cachedType = packageBinding.getType0(binaryBinding.compoundName[binaryBinding.compoundName.length - 1]); + if (cachedType != null) { + if (cachedType.isBinaryBinding()) // sanity check before the cast... at this point the cache should ONLY contain unresolved types + return (BinaryTypeBinding) cachedType; + + UnresolvedReferenceBinding unresolvedType = (UnresolvedReferenceBinding) cachedType; + unresolvedType.resolvedType = binaryBinding; + updateArrayCache(unresolvedType, binaryBinding); + } + + packageBinding.addType(binaryBinding); + binaryBinding.cachePartsFrom(binaryType, needFieldsAndMethods); + return binaryBinding; +} +/* Used to create packages from the package statement. +*/ + +PackageBinding createPackage(char[][] compoundName) { + PackageBinding packageBinding = getPackage0(compoundName[0]); + if (packageBinding == null || packageBinding == theNotFoundPackage) { + packageBinding = new PackageBinding(compoundName[0], this); + knownPackages.put(compoundName[0], packageBinding); + } + + for (int i = 1, length = compoundName.length; i < length; i++) { + // check to see if it collides with a known type... + // this case can only happen if the package does not exist as a directory in the file system + // otherwise when the source type was defined, the correct error would have been reported + // unless its an unresolved type which is referenced from an inconsistent class file + ReferenceBinding type = packageBinding.getType0(compoundName[i]); + if (type != null && type != theNotFoundType && !(type instanceof UnresolvedReferenceBinding)) + return null; + + PackageBinding parent = packageBinding; + if ((packageBinding = parent.getPackage0(compoundName[i])) == null || packageBinding == theNotFoundPackage) { + // if the package is unknown, check to see if a type exists which would collide with the new package + // catches the case of a package statement of: package java.lang.Object; + // since the package can be added after a set of source files have already been compiled, we need + // whenever a package statement is encountered + if (nameEnvironment.findType(compoundName[i], parent.compoundName) != null) + return null; + + packageBinding = new PackageBinding(CharOperation.subarray(compoundName, 0, i + 1), parent, this); + parent.addPackage(packageBinding); + } + } + return packageBinding; +} +/* Answer the type for the compoundName if it exists in the cache. +* Answer theNotFoundType if it could not be resolved the first time +* it was looked up, otherwise answer null. +* +* NOTE: Do not use for nested types... the answer is NOT the same for a.b.C or a.b.C.D.E +* assuming C is a type in both cases. In the a.b.C.D.E case, null is the answer. +*/ + +public ReferenceBinding getCachedType(char[][] compoundName) { + if (compoundName.length == 1) { + if (defaultPackage == null) + return null; + return defaultPackage.getType0(compoundName[0]); + } + + PackageBinding packageBinding = getPackage0(compoundName[0]); + if (packageBinding == null || packageBinding == theNotFoundPackage) + return null; + + for (int i = 1, packageLength = compoundName.length - 1; i < packageLength; i++) + if ((packageBinding = packageBinding.getPackage0(compoundName[i])) == null || packageBinding == theNotFoundPackage) + return null; + return packageBinding.getType0(compoundName[compoundName.length - 1]); +} +/* Answer the top level package named name if it exists in the cache. +* Answer theNotFoundPackage if it could not be resolved the first time +* it was looked up, otherwise answer null. +* +* NOTE: Senders must convert theNotFoundPackage into a real problem +* package if its to returned. +*/ + +PackageBinding getPackage0(char[] name) { + return knownPackages.get(name); +} +/* Answer the top level package named name. +* Ask the oracle for the package if its not in the cache. +* Answer null if the package cannot be found. +*/ + +PackageBinding getTopLevelPackage(char[] name) { + PackageBinding packageBinding = getPackage0(name); + if (packageBinding != null) { + if (packageBinding == theNotFoundPackage) + return null; + else + return packageBinding; + } + + if (nameEnvironment.isPackage(null, name)) { + knownPackages.put(name, packageBinding = new PackageBinding(name, this)); + return packageBinding; + } + + knownPackages.put(name, theNotFoundPackage); // saves asking the oracle next time + return null; +} +/* Answer the type corresponding to the compoundName. +* Ask the oracle for the type if its not in the cache. +* Answer null if the type cannot be found... likely a fatal error. +*/ + +public ReferenceBinding getType(char[][] compoundName) { + ReferenceBinding referenceBinding; + + if (compoundName.length == 1) { + if (defaultPackage == null) + return null; + + if ((referenceBinding = defaultPackage.getType0(compoundName[0])) == null) { + PackageBinding packageBinding = getPackage0(compoundName[0]); + if (packageBinding != null && packageBinding != theNotFoundPackage) + return null; // collides with a known package... should not call this method in such a case + referenceBinding = askForType(defaultPackage, compoundName[0]); + } + } else { + PackageBinding packageBinding = getPackage0(compoundName[0]); + if (packageBinding == theNotFoundPackage) + return null; + + if (packageBinding != null) { + for (int i = 1, packageLength = compoundName.length - 1; i < packageLength; i++) { + if ((packageBinding = packageBinding.getPackage0(compoundName[i])) == null) + break; + if (packageBinding == theNotFoundPackage) + return null; + } + } + + if (packageBinding == null) + referenceBinding = askForType(compoundName); + else if ((referenceBinding = packageBinding.getType0(compoundName[compoundName.length - 1])) == null) + referenceBinding = askForType(packageBinding, compoundName[compoundName.length - 1]); + } + + if (referenceBinding == null || referenceBinding == theNotFoundType) + return null; + if (referenceBinding instanceof UnresolvedReferenceBinding) + referenceBinding = ((UnresolvedReferenceBinding) referenceBinding).resolve(this); + + // compoundName refers to a nested type incorrectly (i.e. package1.A$B) + if (referenceBinding.isNestedType()) + return new ProblemReferenceBinding(compoundName, InternalNameProvided); + else + return referenceBinding; +} +/* Answer the type corresponding to the name from the binary file. +* Does not ask the oracle for the type if its not found in the cache... instead an +* unresolved type is returned which must be resolved before used. +* +* NOTE: Does NOT answer base types nor array types! +* +* NOTE: Aborts compilation if the class file cannot be found. +*/ + +ReferenceBinding getTypeFromConstantPoolName(char[] signature, int start, int end) { + if (end == -1) + end = signature.length - 1; + + char[][] compoundName = CharOperation.splitOn('/', signature, start, end); + ReferenceBinding binding = getCachedType(compoundName); + if (binding == null) { + PackageBinding packageBinding = computePackageFrom(compoundName); + binding = new UnresolvedReferenceBinding(compoundName, packageBinding); + packageBinding.addType(binding); + } else if (binding == theNotFoundType) { + problemReporter.isClassPathCorrect(compoundName, null); + return null; // will not get here since the above error aborts the compilation + } + return binding; +} +/* Answer the type corresponding to the signature from the binary file. +* Does not ask the oracle for the type if its not found in the cache... instead an +* unresolved type is returned which must be resolved before used. +* +* NOTE: Does answer base types & array types. +* +* NOTE: Aborts compilation if the class file cannot be found. +*/ + +TypeBinding getTypeFromSignature(char[] signature, int start, int end) { + int dimension = 0; + while (signature[start] == '[') { + start++; + dimension++; + } + if (end == -1) + end = signature.length - 1; + + // Just switch on signature[start] - the L case is the else + TypeBinding binding = null; + if (start == end) { + switch (signature[start]) { + case 'I' : + binding = IntBinding; + break; + case 'Z' : + binding = BooleanBinding; + break; + case 'V' : + binding = VoidBinding; + break; + case 'C' : + binding = CharBinding; + break; + case 'D' : + binding = DoubleBinding; + break; + case 'B' : + binding = ByteBinding; + break; + case 'F' : + binding = FloatBinding; + break; + case 'J' : + binding = LongBinding; + break; + case 'S' : + binding = ShortBinding; + break; + default : + throw new Error(Util.bind("error.undefinedBaseType",String.valueOf(signature[start]))); //$NON-NLS-1$ + } + } else { + binding = getTypeFromConstantPoolName(signature, start + 1, end - 1); + } + + if (dimension == 0) + return binding; + else + return createArrayType(binding, dimension); +} +/* Ask the oracle if a package exists named name in the package named compoundName. +*/ + +boolean isPackage(char[][] compoundName, char[] name) { + if (compoundName == null || compoundName.length == 0) + return nameEnvironment.isPackage(null, name); + else + return nameEnvironment.isPackage(compoundName, name); +} +// The method verifier is lazily initialized to guarantee the receiver, the compiler & the oracle are ready. + +public MethodVerifier methodVerifier() { + if (verifier == null) + verifier = new MethodVerifier(this); + return verifier; +} +public void reset() { + this.defaultPackage = new PackageBinding(this); // assume the default package always exists + this.defaultImports = null; + this.knownPackages = new HashtableOfPackage(); + + this.verifier = null; + for (int i = this.uniqueArrayBindings.length; --i >= 0;) + this.uniqueArrayBindings[i] = null; + this.uniqueArrayBindings[0] = new ArrayBinding[50]; // start off the most common 1 dimension array @ 50 + + for (int i = this.units.length; --i >= 0;) + this.units[i] = null; + this.lastUnitIndex = -1; + this.lastCompletedUnitIndex = -1; + + // name environment has a longer life cycle, and must be reset in + // the code which created it. +} +void updateArrayCache(UnresolvedReferenceBinding unresolvedType, ReferenceBinding resolvedType) { + nextDimension : for (int i = 0, length = uniqueArrayBindings.length; i < length; i++) { + ArrayBinding[] arrayBindings = uniqueArrayBindings[i]; + if (arrayBindings != null) { + for (int j = 0, max = arrayBindings.length; j < max; j++) { + ArrayBinding currentBinding = arrayBindings[j]; + if (currentBinding == null) + continue nextDimension; + if (currentBinding.leafComponentType == unresolvedType) { + currentBinding.leafComponentType = resolvedType; + continue nextDimension; + } + } + } + } +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/MemberTypeBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/MemberTypeBinding.java new file mode 100644 index 0000000..5e106f9 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/MemberTypeBinding.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public final class MemberTypeBinding extends NestedTypeBinding { +public MemberTypeBinding(char[][] compoundName, ClassScope scope, SourceTypeBinding enclosingType) { + super(compoundName, scope, enclosingType); + this.tagBits |= MemberTypeMask; +} +void checkSyntheticArgsAndFields() { + if (this.isStatic()) return; + if (this.isInterface()) return; + this.addSyntheticArgumentAndField(this.enclosingType); +} +/* Answer the receiver's constant pool name. +* +* NOTE: This method should only be used during/after code gen. +*/ + +public char[] constantPoolName() /* java/lang/Object */ { + if (constantPoolName != null) + return constantPoolName; + + return constantPoolName = CharOperation.concat(enclosingType().constantPoolName(), sourceName, '$'); +} +public String toString() { + return "Member type : " + new String(sourceName()) + " " + super.toString(); //$NON-NLS-2$ //$NON-NLS-1$ +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/MethodBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/MethodBinding.java new file mode 100644 index 0000000..1453fef --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/MethodBinding.java @@ -0,0 +1,441 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration; + +public class MethodBinding extends Binding implements BaseTypes, TypeConstants { + public int modifiers; + public char[] selector; + public TypeBinding returnType; + public TypeBinding[] parameters; + public ReferenceBinding[] thrownExceptions; + public ReferenceBinding declaringClass; + + char[] signature; +protected MethodBinding() { +} +public MethodBinding(int modifiers, char[] selector, TypeBinding returnType, TypeBinding[] args, ReferenceBinding[] exceptions, ReferenceBinding declaringClass) { + this.modifiers = modifiers; + this.selector = selector; + this.returnType = returnType; + this.parameters = (args == null || args.length == 0) ? NoParameters : args; + this.thrownExceptions = (exceptions == null || exceptions.length == 0) ? NoExceptions : exceptions; + this.declaringClass = declaringClass; + + // propagate the strictfp & deprecated modifiers + if (this.declaringClass != null) { + if (this.declaringClass.isStrictfp()) + if (!(isNative() || isAbstract())) + this.modifiers |= AccStrictfp; + if (this.declaringClass.isViewedAsDeprecated() && !isDeprecated()) + this.modifiers |= AccDeprecatedImplicitly; + } +} +public MethodBinding(int modifiers, TypeBinding[] args, ReferenceBinding[] exceptions, ReferenceBinding declaringClass) { + this(modifiers, ConstructorDeclaration.ConstantPoolName, VoidBinding, args, exceptions, declaringClass); +} +// special API used to change method declaring class for runtime visibility check +public MethodBinding(MethodBinding initialMethodBinding, ReferenceBinding declaringClass) { + this.modifiers = initialMethodBinding.modifiers; + this.selector = initialMethodBinding.selector; + this.returnType = initialMethodBinding.returnType; + this.parameters = initialMethodBinding.parameters; + this.thrownExceptions = initialMethodBinding.thrownExceptions; + this.declaringClass = declaringClass; +} +/* Answer true if the argument types & the receiver's parameters are equal +*/ + +public final boolean areParametersEqual(MethodBinding method) { + TypeBinding[] args = method.parameters; + if (parameters == args) + return true; + + int length = parameters.length; + if (length != args.length) + return false; + + for (int i = 0; i < length; i++) + if (parameters[i] != args[i]) + return false; + return true; +} +/* API +* Answer the receiver's binding type from Binding.BindingID. +*/ + +public final int bindingType() { + return METHOD; +} +/* Answer true if the receiver is visible to the type provided by the scope. +* InvocationSite implements isSuperAccess() to provide additional information +* if the receiver is protected. +* +* NOTE: This method should ONLY be sent if the receiver is a constructor. +* +* NOTE: Cannot invoke this method with a compilation unit scope. +*/ + +public final boolean canBeSeenBy(InvocationSite invocationSite, Scope scope) { + if (isPublic()) return true; + + SourceTypeBinding invocationType = scope.enclosingSourceType(); + if (invocationType == declaringClass) return true; + + if (isProtected()) { + // answer true if the receiver is in the same package as the invocationType + if (invocationType.fPackage == declaringClass.fPackage) return true; + return invocationSite.isSuperAccess(); + } + + if (isPrivate()) { + // answer true if the invocationType and the declaringClass have a common enclosingType + // already know they are not the identical type + ReferenceBinding outerInvocationType = invocationType; + ReferenceBinding temp = outerInvocationType.enclosingType(); + while (temp != null) { + outerInvocationType = temp; + temp = temp.enclosingType(); + } + + ReferenceBinding outerDeclaringClass = declaringClass; + temp = outerDeclaringClass.enclosingType(); + while (temp != null) { + outerDeclaringClass = temp; + temp = temp.enclosingType(); + } + return outerInvocationType == outerDeclaringClass; + } + + // isDefault() + return invocationType.fPackage == declaringClass.fPackage; +} +/* Answer true if the receiver is visible to the type provided by the scope. +* InvocationSite implements isSuperAccess() to provide additional information +* if the receiver is protected. +* +* NOTE: Cannot invoke this method with a compilation unit scope. +*/ +public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invocationSite, Scope scope) { + if (isPublic()) return true; + + SourceTypeBinding invocationType = scope.enclosingSourceType(); + if (invocationType == declaringClass && invocationType == receiverType) return true; + + if (isProtected()) { + // answer true if the invocationType is the declaringClass or they are in the same package + // OR the invocationType is a subclass of the declaringClass + // AND the receiverType is the invocationType or its subclass + // OR the method is a static method accessed directly through a type + // OR previous assertions are true for one of the enclosing type + if (invocationType == declaringClass) return true; + if (invocationType.fPackage == declaringClass.fPackage) return true; + + ReferenceBinding currentType = invocationType; + int depth = 0; + do { + if (declaringClass.isSuperclassOf(currentType)) { + if (invocationSite.isSuperAccess()){ + return true; + } + // receiverType can be an array binding in one case... see if you can change it + if (receiverType instanceof ArrayBinding){ + return false; + } + if (isStatic()){ + return true; // see 1FMEPDL - return invocationSite.isTypeAccess(); + } + if (currentType == receiverType || currentType.isSuperclassOf((ReferenceBinding) receiverType)){ + if (depth > 0) invocationSite.setDepth(depth); + return true; + } + } + depth++; + currentType = currentType.enclosingType(); + } while (currentType != null); + return false; + } + + if (isPrivate()) { + // answer true if the receiverType is the declaringClass + // AND the invocationType and the declaringClass have a common enclosingType + if (receiverType != declaringClass) return false; + + if (invocationType != declaringClass) { + ReferenceBinding outerInvocationType = invocationType; + ReferenceBinding temp = outerInvocationType.enclosingType(); + while (temp != null) { + outerInvocationType = temp; + temp = temp.enclosingType(); + } + + ReferenceBinding outerDeclaringClass = declaringClass; + temp = outerDeclaringClass.enclosingType(); + while (temp != null) { + outerDeclaringClass = temp; + temp = temp.enclosingType(); + } + if (outerInvocationType != outerDeclaringClass) return false; + } + return true; + } + + // isDefault() + if (invocationType.fPackage != declaringClass.fPackage) return false; + + // receiverType can be an array binding in one case... see if you can change it + if (receiverType instanceof ArrayBinding) + return false; + ReferenceBinding type = (ReferenceBinding) receiverType; + PackageBinding declaringPackage = declaringClass.fPackage; + do { + if (declaringClass == type) return true; + if (declaringPackage != type.fPackage) return false; + } while ((type = type.superclass()) != null); + return false; +} +/* Answer the receiver's constant pool name. +* +* for constructors +* for clinit methods +* or the source name of the method +*/ + +public final char[] constantPoolName() { + return selector; +} +public final int getAccessFlags() { + return modifiers & AccJustFlag; +} +/* Answer true if the receiver is an abstract method +*/ + +public final boolean isAbstract() { + return (modifiers & AccAbstract) != 0; +} +/* Answer true if the receiver is a constructor +*/ + +public final boolean isConstructor() { + return selector == ConstructorDeclaration.ConstantPoolName; +} +protected boolean isConstructorRelated() { + return isConstructor(); +} +/* Answer true if the receiver has default visibility +*/ + +public final boolean isDefault() { + return !isPublic() && !isProtected() && !isPrivate(); +} +/* Answer true if the receiver is a system generated default abstract method +*/ + +public final boolean isDefaultAbstract() { + return (modifiers & AccDefaultAbstract) != 0; +} +/* Answer true if the receiver is a deprecated method +*/ + +public final boolean isDeprecated() { + return (modifiers & AccDeprecated) != 0; +} +/* Answer true if the receiver is final and cannot be overridden +*/ + +public final boolean isFinal() { + return (modifiers & AccFinal) != 0; +} +/* Answer true if the receiver is a native method +*/ + +public final boolean isNative() { + return (modifiers & AccNative) != 0; +} +/* Answer true if the receiver has private visibility +*/ + +public final boolean isPrivate() { + return (modifiers & AccPrivate) != 0; +} +/* Answer true if the receiver has protected visibility +*/ + +public final boolean isProtected() { + return (modifiers & AccProtected) != 0; +} +/* Answer true if the receiver has public visibility +*/ + +public final boolean isPublic() { + return (modifiers & AccPublic) != 0; +} +/* Answer true if the receiver got requested to clear the private modifier + * during private access emulation. + */ + +public final boolean isRequiredToClearPrivateModifier() { + return (modifiers & AccClearPrivateModifier) != 0; +} +/* Answer true if the receiver is a static method +*/ + +public final boolean isStatic() { + return (modifiers & AccStatic) != 0; +} +/* Answer true if all float operations must adher to IEEE 754 float/double rules +*/ + +public final boolean isStrictfp() { + return (modifiers & AccStrictfp) != 0; +} +/* Answer true if the receiver is a synchronized method +*/ + +public final boolean isSynchronized() { + return (modifiers & AccSynchronized) != 0; +} +/* Answer true if the receiver has public visibility +*/ + +public final boolean isSynthetic() { + return (modifiers & AccSynthetic) != 0; +} +/* Answer true if the receiver's declaring type is deprecated (or any of its enclosing types) +*/ + +public final boolean isViewedAsDeprecated() { + return (modifiers & AccDeprecated) != 0 || + (modifiers & AccDeprecatedImplicitly) != 0; +} +public char[] readableName() /* foo(int, Thread) */ { + StringBuffer buffer = new StringBuffer(parameters.length + 1 * 20); + if (isConstructor()) + buffer.append(declaringClass.sourceName()); + else + buffer.append(selector); + buffer.append('('); + if (parameters != NoParameters) { + for (int i = 0, length = parameters.length; i < length; i++) { + if (i > 0) + buffer.append(", "); //$NON-NLS-1$ + buffer.append(parameters[i].sourceName()); + } + } + buffer.append(')'); + return buffer.toString().toCharArray(); +} +protected final void selector(char[] selector) { + this.selector = selector; + this.signature = null; +} +/* Answer the receiver's signature. +* +* NOTE: This method should only be used during/after code gen. +* The signature is cached so if the signature of the return type or any parameter +* type changes, the cached state is invalid. +*/ + +public final char[] signature() /* (ILjava/lang/Thread;)Ljava/lang/Object; */ { + if (signature != null) + return signature; + + StringBuffer buffer = new StringBuffer(parameters.length + 1 * 20); + buffer.append('('); + if (isConstructorRelated() && declaringClass.isNestedType()) { + // take into account the synthetic argument type signatures as well + ReferenceBinding[] syntheticArgumentTypes = declaringClass.syntheticEnclosingInstanceTypes(); + int count = syntheticArgumentTypes == null ? 0 : syntheticArgumentTypes.length; + for (int i = 0; i < count; i++) + buffer.append(syntheticArgumentTypes[i].signature()); + SyntheticArgumentBinding[] syntheticArguments = declaringClass.syntheticOuterLocalVariables(); + count = syntheticArguments == null ? 0 : syntheticArguments.length; + for (int i = 0; i < count; i++) + buffer.append(syntheticArguments[i].type.signature()); + } + if (parameters != NoParameters) + for (int i = 0, length = parameters.length; i < length; i++) + buffer.append(parameters[i].signature()); + buffer.append(')'); + buffer.append(returnType.signature()); + return signature = buffer.toString().toCharArray(); +} +public final int sourceEnd() { + AbstractMethodDeclaration method = sourceMethod(); + if (method == null) + return 0; + else + return method.sourceEnd; +} +AbstractMethodDeclaration sourceMethod() { + SourceTypeBinding sourceType; + try { + sourceType = (SourceTypeBinding) declaringClass; + } catch (ClassCastException e) { + return null; + } + + AbstractMethodDeclaration[] methods = sourceType.scope.referenceContext.methods; + for (int i = methods.length; --i >= 0;) + if (this == methods[i].binding) + return methods[i]; + return null; +} +public final int sourceStart() { + AbstractMethodDeclaration method = sourceMethod(); + if (method == null) + return 0; + else + return method.sourceStart; +} +/* During private access emulation, the binding can be requested to loose its + * private visibility when the class file is dumped. + */ + +public final void tagForClearingPrivateModifier() { + modifiers |= AccClearPrivateModifier; +} +public String toString() { + String s = (returnType != null) ? returnType.debugName() : "NULL TYPE"; //$NON-NLS-1$ + s += " "; //$NON-NLS-1$ + s += (selector != null) ? new String(selector) : "UNNAMED METHOD"; //$NON-NLS-1$ + + s += "("; //$NON-NLS-1$ + if (parameters != null) { + if (parameters != NoParameters) { + for (int i = 0, length = parameters.length; i < length; i++) { + if (i > 0) + s += ", "; //$NON-NLS-1$ + s += (parameters[i] != null) ? parameters[i].debugName() : "NULL TYPE"; //$NON-NLS-1$ + } + } + } else { + s += "NULL PARAMETERS"; //$NON-NLS-1$ + } + s += ") "; //$NON-NLS-1$ + + if (thrownExceptions != null) { + if (thrownExceptions != NoExceptions) { + s += "throws "; //$NON-NLS-1$ + for (int i = 0, length = thrownExceptions.length; i < length; i++) { + if (i > 0) + s += ", "; //$NON-NLS-1$ + s += (thrownExceptions[i] != null) ? thrownExceptions[i].debugName() : "NULL TYPE"; //$NON-NLS-1$ + } + } + } else { + s += "NULL THROWN EXCEPTIONS"; //$NON-NLS-1$ + } + return s; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/MethodScope.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/MethodScope.java new file mode 100644 index 0000000..7ec902b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/MethodScope.java @@ -0,0 +1,400 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.QualifiedNameReference; +import net.sourceforge.phpdt.internal.compiler.ast.SingleNameReference; +import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo; +import net.sourceforge.phpdt.internal.compiler.flow.UnconditionalFlowInfo; +import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext; +import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter; + +/** + * Particular block scope used for methods, constructors or clinits, representing + * its outermost blockscope. Note also that such a scope will be provided to enclose + * field initializers subscopes as well. + */ +public class MethodScope extends BlockScope { + + public ReferenceContext referenceContext; + public boolean needToCompactLocalVariables; + public boolean isStatic; // method modifier or initializer one + + //fields used in the TC process (no real meaning) + public static final int NotInFieldDecl = -1; //must be a negative value + public boolean isConstructorCall = false; //modified on the fly by the TC + public int fieldDeclarationIndex = NotInFieldDecl; + //modified on the fly by the TC + + public int analysisIndex; // for setting flow-analysis id + + public boolean isPropagatingInnerClassEmulation; + + // for local variables table attributes + public int lastIndex = 0; + public long[] definiteInits = new long[4]; + public long[][] extraDefiniteInits = new long[4][]; + + public MethodScope( + ClassScope parent, + ReferenceContext context, + boolean isStatic) { + + super(METHOD_SCOPE, parent); + locals = new LocalVariableBinding[5]; + this.referenceContext = context; + this.isStatic = isStatic; + this.startIndex = 0; + } + + /* Spec : 8.4.3 & 9.4 + */ + private void checkAndSetModifiersForConstructor(MethodBinding methodBinding) { + + int modifiers = methodBinding.modifiers; + if ((modifiers & AccAlternateModifierProblem) != 0) + problemReporter().duplicateModifierForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + if (((ConstructorDeclaration) referenceContext).isDefaultConstructor) { + if (methodBinding.declaringClass.isPublic()) + modifiers |= AccPublic; + else if (methodBinding.declaringClass.isProtected()) + modifiers |= AccProtected; + } + + // after this point, tests on the 16 bits reserved. + int realModifiers = modifiers & AccJustFlag; + + // check for abnormal modifiers + int unexpectedModifiers = + ~(AccPublic | AccPrivate | AccProtected | AccStrictfp); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + else if ( + (((AbstractMethodDeclaration) referenceContext).modifiers & AccStrictfp) != 0) + // must check the parse node explicitly + problemReporter().illegalModifierForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + // check for incompatible modifiers in the visibility bits, isolate the visibility bits + int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate); + if ((accessorBits & (accessorBits - 1)) != 0) { + problemReporter().illegalVisibilityModifierCombinationForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + // need to keep the less restrictive + if ((accessorBits & AccPublic) != 0) { + if ((accessorBits & AccProtected) != 0) + modifiers ^= AccProtected; + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + if ((accessorBits & AccProtected) != 0) + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + + // if the receiver's declaring class is a private nested type, then make sure the receiver is not private (causes problems for inner type emulation) + if (methodBinding.declaringClass.isPrivate()) + if ((modifiers & AccPrivate) != 0) + modifiers ^= AccPrivate; + + methodBinding.modifiers = modifiers; + } + + /* Spec : 8.4.3 & 9.4 + */ + private void checkAndSetModifiersForMethod(MethodBinding methodBinding) { + + int modifiers = methodBinding.modifiers; + if ((modifiers & AccAlternateModifierProblem) != 0) + problemReporter().duplicateModifierForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + // after this point, tests on the 16 bits reserved. + int realModifiers = modifiers & AccJustFlag; + + // set the requested modifiers for a method in an interface + if (methodBinding.declaringClass.isInterface()) { + if ((realModifiers & ~(AccPublic | AccAbstract)) != 0) + problemReporter().illegalModifierForInterfaceMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + return; + } + + // check for abnormal modifiers + int unexpectedModifiers = + ~( + AccPublic + | AccPrivate + | AccProtected + | AccAbstract + | AccStatic + | AccFinal + | AccSynchronized + | AccNative + | AccStrictfp); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + // check for incompatible modifiers in the visibility bits, isolate the visibility bits + int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate); + if ((accessorBits & (accessorBits - 1)) != 0) { + problemReporter().illegalVisibilityModifierCombinationForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + // need to keep the less restrictive + if ((accessorBits & AccPublic) != 0) { + if ((accessorBits & AccProtected) != 0) + modifiers ^= AccProtected; + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + if ((accessorBits & AccProtected) != 0) + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + + // check for modifiers incompatible with abstract modifier + if ((modifiers & AccAbstract) != 0) { + int incompatibleWithAbstract = + AccPrivate | AccStatic | AccFinal | AccSynchronized | AccNative | AccStrictfp; + if ((modifiers & incompatibleWithAbstract) != 0) + problemReporter().illegalAbstractModifierCombinationForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + if (!methodBinding.declaringClass.isAbstract()) + problemReporter().abstractMethodInAbstractClass( + (SourceTypeBinding) methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + } + + /* DISABLED for backward compatibility with javac (if enabled should also mark private methods as final) + // methods from a final class are final : 8.4.3.3 + if (methodBinding.declaringClass.isFinal()) + modifiers |= AccFinal; + */ + // native methods cannot also be tagged as strictfp + if ((modifiers & AccNative) != 0 && (modifiers & AccStrictfp) != 0) + problemReporter().nativeMethodsCannotBeStrictfp( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + // static members are only authorized in a static member or top level type + if (((realModifiers & AccStatic) != 0) + && methodBinding.declaringClass.isNestedType() + && !methodBinding.declaringClass.isStatic()) + problemReporter().unexpectedStaticModifierForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + methodBinding.modifiers = modifiers; + } + + /* Error management: + * keep null for all the errors that prevent the method to be created + * otherwise return a correct method binding (but without the element + * that caused the problem) : ie : Incorrect thrown exception + */ + MethodBinding createMethod(AbstractMethodDeclaration method) { + + // is necessary to ensure error reporting + this.referenceContext = method; + method.scope = this; + SourceTypeBinding declaringClass = referenceType().binding; + int modifiers = method.modifiers | AccUnresolved; + if (method.isConstructor()) { + method.binding = new MethodBinding(modifiers, null, null, declaringClass); + checkAndSetModifiersForConstructor(method.binding); + } else { + if (declaringClass.isInterface()) + modifiers |= AccPublic | AccAbstract; + method.binding = + new MethodBinding(modifiers, method.selector, null, null, null, declaringClass); + checkAndSetModifiersForMethod(method.binding); + } + + this.isStatic = method.binding.isStatic(); + return method.binding; + } + + /* Overridden to detect the error case inside an explicit constructor call: + + class X { + int i; + X myX; + X(X x) { + this(i, myX.i, x.i); // same for super calls... only the first 2 field accesses are errors + } + } + */ + public FieldBinding findField( + TypeBinding receiverType, + char[] fieldName, + InvocationSite invocationSite) { + + FieldBinding field = super.findField(receiverType, fieldName, invocationSite); + if (field == null) + return null; + if (!field.isValidBinding()) + return field; // answer the error field + if (field.isStatic()) + return field; // static fields are always accessible + + if (!isConstructorCall || receiverType != enclosingSourceType()) + return field; + + if (invocationSite instanceof SingleNameReference) + return new ProblemFieldBinding( + field.declaringClass, + fieldName, + NonStaticReferenceInConstructorInvocation); + if (invocationSite instanceof QualifiedNameReference) { + // look to see if the field is the first binding + QualifiedNameReference name = (QualifiedNameReference) invocationSite; + if (name.binding == null) + // only true when the field is the fieldbinding at the beginning of name's tokens + return new ProblemFieldBinding( + field.declaringClass, + fieldName, + NonStaticReferenceInConstructorInvocation); + } + return field; + } + + public boolean isInsideInitializer() { + + return (referenceContext instanceof TypeDeclaration); + } + + public boolean isInsideInitializerOrConstructor() { + + return (referenceContext instanceof TypeDeclaration) + || (referenceContext instanceof ConstructorDeclaration); + } + + /* Answer the problem reporter to use for raising new problems. + * + * Note that as a side-effect, this updates the current reference context + * (unit, type or method) in case the problem handler decides it is necessary + * to abort. + */ + public ProblemReporter problemReporter() { + + MethodScope outerMethodScope; + if ((outerMethodScope = outerMostMethodScope()) == this) { + ProblemReporter problemReporter = referenceCompilationUnit().problemReporter; + problemReporter.referenceContext = referenceContext; + return problemReporter; + } else { + return outerMethodScope.problemReporter(); + } + } + + public final int recordInitializationStates(FlowInfo flowInfo) { + + if ((flowInfo == FlowInfo.DeadEnd) || (flowInfo.isFakeReachable())) { + return -1; + } + UnconditionalFlowInfo unconditionalFlowInfo = flowInfo.unconditionalInits(); + long[] extraInits = unconditionalFlowInfo.extraDefiniteInits; + long inits = unconditionalFlowInfo.definiteInits; + checkNextEntry : for (int i = lastIndex; --i >= 0;) { + if (definiteInits[i] == inits) { + long[] otherInits = extraDefiniteInits[i]; + if ((extraInits != null) && (otherInits != null)) { + if (extraInits.length == otherInits.length) { + int j, max; + for (j = 0, max = extraInits.length; j < max; j++) { + if (extraInits[j] != otherInits[j]) { + continue checkNextEntry; + } + } + return i; + } + } else { + if ((extraInits == null) && (otherInits == null)) { + return i; + } + } + } + } + + // add a new entry + if (definiteInits.length == lastIndex) { + // need a resize + System.arraycopy( + definiteInits, + 0, + (definiteInits = new long[lastIndex + 20]), + 0, + lastIndex); + System.arraycopy( + extraDefiniteInits, + 0, + (extraDefiniteInits = new long[lastIndex + 20][]), + 0, + lastIndex); + } + definiteInits[lastIndex] = inits; + if (extraInits != null) { + extraDefiniteInits[lastIndex] = new long[extraInits.length]; + System.arraycopy( + extraInits, + 0, + extraDefiniteInits[lastIndex], + 0, + extraInits.length); + } + return lastIndex++; + } + + /* Answer the reference type of this scope. + * + * i.e. the nearest enclosing type of this scope. + */ + public TypeDeclaration referenceType() { + + return (TypeDeclaration) ((ClassScope) parent).referenceContext; + } + + String basicToString(int tab) { + + String newLine = "\n"; //$NON-NLS-1$ + for (int i = tab; --i >= 0;) + newLine += "\t"; //$NON-NLS-1$ + + String s = newLine + "--- Method Scope ---"; //$NON-NLS-1$ + newLine += "\t"; //$NON-NLS-1$ + s += newLine + "locals:"; //$NON-NLS-1$ + for (int i = 0; i < localIndex; i++) + s += newLine + "\t" + locals[i].toString(); //$NON-NLS-1$ + s += newLine + "startIndex = " + startIndex; //$NON-NLS-1$ + s += newLine + "isConstructorCall = " + isConstructorCall; //$NON-NLS-1$ + s += newLine + "fieldDeclarationIndex = " + fieldDeclarationIndex; //$NON-NLS-1$ + return s; + } + +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/MethodVerifier.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/MethodVerifier.java new file mode 100644 index 0000000..1debb98 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/MethodVerifier.java @@ -0,0 +1,879 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.ast.MethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; +import net.sourceforge.phpdt.internal.compiler.util.HashtableOfObject; + +public final class MethodVerifier implements TagBits, TypeConstants { + SourceTypeBinding type; + HashtableOfObject inheritedMethods; + HashtableOfObject currentMethods; + ReferenceBinding runtimeException; + ReferenceBinding errorException; +/* +Binding creation is responsible for reporting all problems with types: + - all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations - abstract/final) + - plus invalid modifiers given the context (the verifier did not do this before) + - qualified name collisions between a type and a package (types in default packages are excluded) + - all type hierarchy problems: + - cycles in the superclass or superinterface hierarchy + - an ambiguous, invisible or missing superclass or superinterface + - extending a final class + - extending an interface instead of a class + - implementing a class instead of an interface + - implementing the same interface more than once (ie. duplicate interfaces) + - with nested types: + - shadowing an enclosing type's source name + - defining a static class or interface inside a non-static nested class + - defining an interface as a local type (local types can only be classes) + +verifyTypeStructure + + | hasHierarchyProblem superclass current names interfaces interfacesByIndentity duplicateExists invalidType | + + (type basicModifiers anyMask: AccModifierProblem | AccAlternateModifierProblem) ifTrue: [ + self reportModifierProblemsOnType: type]. + + type controller isJavaDefaultPackage ifFalse: [ + (nameEnvironment class doesPackageExistNamed: type javaQualifiedName) ifTrue: [ + problemSummary + reportVerificationProblem: #CollidesWithPackage + args: (Array with: type javaQualifiedName) + severity: nil + forType: type]]. + + hasHierarchyProblem := false. + + type isJavaClass + ifTrue: [ + (superclass := self superclassFor: type) ~~ nil ifTrue: [ + superclass isBuilderClass ifTrue: [ + superclass := superclass newClass]. + superclass isJavaMissing + ifTrue: [ + hasHierarchyProblem := true. + type javaSuperclassIsMissing ifTrue: [ + problemSummary + reportVerificationProblem: #MissingSuperclass + args: (Array with: superclass javaQualifiedName with: superclass unmatchedDescriptor) + severity: nil + forType: type]. + type javaSuperclassCreatesCycle ifTrue: [ + problemSummary + reportVerificationProblem: #CyclicSuperclass + args: (Array with: superclass javaQualifiedName) + severity: nil + forType: type]. + type javaSuperclassIsInterface ifTrue: [ + problemSummary + reportVerificationProblem: #ClassCannotExtendAnInterface + args: (Array with: superclass javaQualifiedName) + severity: nil + forType: type]] + ifFalse: [ + "NOTE: If type is a Java class and its superclass is + a valid descriptor then it should NEVER be an interface." + + superclass isJavaFinal ifTrue: [ + problemSummary + reportVerificationProblem: #ClassCannotExtendFinalClass + args: nil + severity: nil + forType: type]]]] + ifFalse: [ + type isJavaLocalType ifTrue: [ + problemSummary + reportVerificationProblem: #CannotDefineLocalInterface + args: nil + severity: nil + forType: type]]. + + type isJavaNestedType ifTrue: [ + (current := type) sourceName notEmpty ifTrue: [ + names := Set new. + [(current := current enclosingType) ~~ nil] whileTrue: [ + names add: current sourceName]. + + (names includes: type sourceName) ifTrue: [ + problemSummary + reportVerificationProblem: #NestedTypeCannotShadowTypeName + args: nil + severity: nil + forType: type]]. + + (type enclosingType isJavaNestedType and: [type enclosingType isJavaClass]) ifTrue: [ + type enclosingType isJavaStatic ifFalse: [ + type isJavaClass + ifTrue: [ + type isJavaStatic ifTrue: [ + problemSummary + reportVerificationProblem: #StaticClassCannotExistInNestedClass + args: nil + severity: nil + forType: type]] + ifFalse: [ + problemSummary + reportVerificationProblem: #InterfaceCannotExistInNestedClass + args: nil + severity: nil + forType: type]]]]. + + (interfaces := newClass superinterfaces) notEmpty ifTrue: [ + interfacesByIndentity := interfaces asSet. + duplicateExists := interfaces size ~~ interfacesByIndentity size. + + interfacesByIndentity do: [:interface | + duplicateExists ifTrue: [ + (interfaces occurrencesOf: interface) > 1 ifTrue: [ + problemSummary + reportVerificationProblem: #InterfaceIsSpecifiedMoreThanOnce + args: (Array with: interface javaQualifiedName) + severity: nil + forType: type]]. + + interface isJavaMissing ifTrue: [ + hasHierarchyProblem := true. + interface basicClass == JavaInterfaceIsClass basicClass + ifTrue: [ + problemSummary + reportVerificationProblem: #UsingClassWhereInterfaceIsRequired + args: (Array with: interface javaQualifiedName) + severity: nil + forType: type] + ifFalse: [ + interface basicClass == JavaMissingInterface basicClass + ifTrue: [ + problemSummary + reportVerificationProblem: #MissingInterface + args: (Array with: interface javaQualifiedName with: interface unmatchedDescriptor) + severity: nil + forType: type] + ifFalse: [ + problemSummary + reportVerificationProblem: #CyclicSuperinterface + args: (Array with: interface javaQualifiedName) + severity: nil + forType: type]]]]]. + + hasHierarchyProblem ifFalse: [ + "Search up the type's hierarchy for + 1. missing superclass, + 2. superclass cycle, or + 3. superclass is interface." + (invalidType := newClass findFirstInvalidSupertypeSkipping: EsIdentitySet new) ~~ nil ifTrue: [ + problemSummary + reportVerificationProblem: #HasHierarchyProblem + args: (Array with: invalidType javaReadableName) + severity: nil + forType: type]] + +reportModifierProblemsOnType: aType + + (type basicModifiers anyMask: AccAlternateModifierProblem) ifTrue: [ + (type basicModifiers anyMask: AccModifierProblem) + ifTrue: [ + ^problemSummary + reportVerificationProblem: #OnlyOneVisibilityModifierAllowed + args: nil + severity: nil + forType: aType] + ifFalse: [ + ^problemSummary + reportVerificationProblem: #DuplicateModifier + args: nil + severity: nil + forType: aType]]. + + type isJavaInterface ifTrue: [ + ^problemSummary + reportVerificationProblem: #IllegalModifierForInterface + args: nil + severity: nil + forType: aType]. + + (type basicModifiers allMask: AccAbstract | AccFinal) ifTrue: [ + ^problemSummary + reportVerificationProblem: #IllegalModifierCombinationAbstractFinal + args: nil + severity: nil + forType: aType]. + + ^problemSummary + reportVerificationProblem: #IllegalModifierForClass + args: nil + severity: nil + forType: aType + +void reportModifierProblems() { + if (this.type.isAbstract() && this.type.isFinal()) + this.problemReporter.illegalModifierCombinationAbstractFinal(this.type); + + // Should be able to detect all 3 problems NOT just 1 + if ((type.modifiers() & Modifiers.AccAlternateModifierProblem) == 0) { + if (this.type.isInterface()) + this.problemReporter.illegalModifierForInterface(this.type); + else + this.problemReporter.illegalModifier(this.type); + } else { + if ((type.modifiers() & Modifiers.AccModifierProblem) != 0) + this.problemReporter.onlyOneVisibilityModifierAllowed(this.type); + else + this.problemReporter.duplicateModifier(this.type); + } +} +*/ +public MethodVerifier(LookupEnvironment environment) { + this.type = null; // Initialized with the public method verify(SourceTypeBinding) + this.inheritedMethods = null; + this.currentMethods = null; + this.runtimeException = null; + this.errorException = null; +} +private void checkAgainstInheritedMethods(MethodBinding currentMethod, MethodBinding[] methods, int length) { + for (int i = length; --i >= 0;) { + MethodBinding inheritedMethod = methods[i]; + if (currentMethod.returnType != inheritedMethod.returnType) { + this.problemReporter(currentMethod).incompatibleReturnType(currentMethod, inheritedMethod); + } else if (currentMethod.isStatic() != inheritedMethod.isStatic()) { // Cannot override a static method or hide an instance method + this.problemReporter(currentMethod).staticAndInstanceConflict(currentMethod, inheritedMethod); + } else { + if (currentMethod.thrownExceptions != NoExceptions) + this.checkExceptions(currentMethod, inheritedMethod); + if (inheritedMethod.isFinal()) + this.problemReporter(currentMethod).finalMethodCannotBeOverridden(currentMethod, inheritedMethod); + if (!this.isAsVisible(currentMethod, inheritedMethod)) + this.problemReporter(currentMethod).visibilityConflict(currentMethod, inheritedMethod); + if (inheritedMethod.isViewedAsDeprecated()) + if (!currentMethod.isViewedAsDeprecated()) + this.problemReporter(currentMethod).overridesDeprecatedMethod(currentMethod, inheritedMethod); + } + } +} +/* +"8.4.4" +Verify that newExceptions are all included in inheritedExceptions. +Assumes all exceptions are valid and throwable. +Unchecked exceptions (compatible with runtime & error) are ignored (see the spec on pg. 203). +*/ + +private void checkExceptions(MethodBinding newMethod, MethodBinding inheritedMethod) { + ReferenceBinding[] newExceptions = newMethod.thrownExceptions; + ReferenceBinding[] inheritedExceptions = inheritedMethod.thrownExceptions; + for (int i = newExceptions.length; --i >= 0;) { + ReferenceBinding newException = newExceptions[i]; + int j = inheritedExceptions.length; + while (--j > -1 && !this.isSameClassOrSubclassOf(newException, inheritedExceptions[j])); + if (j == -1) + if (!(newException.isCompatibleWith(this.runtimeException()) || newException.isCompatibleWith(this.errorException()))) + this.problemReporter(newMethod).incompatibleExceptionInThrowsClause(this.type, newMethod, inheritedMethod, newException); + } +} +private void checkInheritedMethods(MethodBinding[] methods, int length) { + TypeBinding returnType = methods[0].returnType; + int index = length; + while ((--index > 0) && (returnType == methods[index].returnType)); + if (index > 0) { // All inherited methods do NOT have the same vmSignature + this.problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length); + return; + } + + MethodBinding concreteMethod = null; + if (!type.isInterface()){ // ignore concrete methods for interfaces + for (int i = length; --i >= 0;) // Remember that only one of the methods can be non-abstract + if (!methods[i].isAbstract()) { + concreteMethod = methods[i]; + break; + } + } + if (concreteMethod == null) { + if (this.type.isClass() && !this.type.isAbstract()) { + for (int i = length; --i >= 0;) + if (!mustImplementAbstractMethod(methods[i])) + return; // in this case, we have already reported problem against the concrete superclass + + TypeDeclaration typeDeclaration = this.type.scope.referenceContext; + if (typeDeclaration != null) { + MethodDeclaration missingAbstractMethod = typeDeclaration.addMissingAbstractMethodFor(methods[0]); + missingAbstractMethod.scope.problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]); + } else { + this.problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]); + } + } + return; + } + + MethodBinding[] abstractMethods = new MethodBinding[length - 1]; + index = 0; + for (int i = length; --i >= 0;) + if (methods[i] != concreteMethod) + abstractMethods[index++] = methods[i]; + + // Remember that interfaces can only define public instance methods + if (concreteMethod.isStatic()) + // Cannot inherit a static method which is specified as an instance method by an interface + this.problemReporter().staticInheritedMethodConflicts(type, concreteMethod, abstractMethods); + if (!concreteMethod.isPublic()) + // Cannot reduce visibility of a public method specified by an interface + this.problemReporter().inheritedMethodReducesVisibility(type, concreteMethod, abstractMethods); + if (concreteMethod.thrownExceptions != NoExceptions) + for (int i = abstractMethods.length; --i >= 0;) + this.checkExceptions(concreteMethod, abstractMethods[i]); +} +/* +For each inherited method identifier (message pattern - vm signature minus the return type) + if current method exists + if current's vm signature does not match an inherited signature then complain + else compare current's exceptions & visibility against each inherited method + else + if inherited methods = 1 + if inherited is abstract && type is NOT an interface or abstract, complain + else + if vm signatures do not match complain + else + find the concrete implementation amongst the abstract methods (can only be 1) + if one exists then + it must be a public instance method + compare concrete's exceptions against each abstract method + else + complain about missing implementation only if type is NOT an interface or abstract +*/ + +private void checkMethods() { + boolean mustImplementAbstractMethods = this.type.isClass() && !this.type.isAbstract(); + char[][] methodSelectors = this.inheritedMethods.keyTable; + for (int s = methodSelectors.length; --s >= 0;) { + if (methodSelectors[s] != null) { + MethodBinding[] current = (MethodBinding[]) this.currentMethods.get(methodSelectors[s]); + MethodBinding[] inherited = (MethodBinding[]) this.inheritedMethods.valueTable[s]; + + int index = -1; + MethodBinding[] matchingInherited = new MethodBinding[inherited.length]; + if (current != null) { + for (int i = 0, length1 = current.length; i < length1; i++) { + while (index >= 0) matchingInherited[index--] = null; // clear the previous contents of the matching methods + MethodBinding currentMethod = current[i]; + for (int j = 0, length2 = inherited.length; j < length2; j++) { + if (inherited[j] != null && currentMethod.areParametersEqual(inherited[j])) { + matchingInherited[++index] = inherited[j]; + inherited[j] = null; // do not want to find it again + } + } + if (index >= 0) + this.checkAgainstInheritedMethods(currentMethod, matchingInherited, index + 1); // pass in the length of matching + } + } + for (int i = 0, length = inherited.length; i < length; i++) { + while (index >= 0) matchingInherited[index--] = null; // clear the previous contents of the matching methods + if (inherited[i] != null) { + matchingInherited[++index] = inherited[i]; + for (int j = i + 1; j < length; j++) { + if (inherited[j] != null && inherited[i].areParametersEqual(inherited[j])) { + matchingInherited[++index] = inherited[j]; + inherited[j] = null; // do not want to find it again + } + } + } + if (index > 0) { + this.checkInheritedMethods(matchingInherited, index + 1); // pass in the length of matching + } else { + if (mustImplementAbstractMethods && index == 0 && matchingInherited[0].isAbstract()) + if (mustImplementAbstractMethod(matchingInherited[0])) { + TypeDeclaration typeDeclaration = this.type.scope.referenceContext; + if (typeDeclaration != null) { + MethodDeclaration missingAbstractMethod = typeDeclaration.addMissingAbstractMethodFor(matchingInherited[0]); + missingAbstractMethod.scope.problemReporter().abstractMethodMustBeImplemented(this.type, matchingInherited[0]); + } else { + this.problemReporter().abstractMethodMustBeImplemented(this.type, matchingInherited[0]); + } + } + } + } + } + } +} +/* +Binding creation is responsible for reporting: + - all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations) + - plus invalid modifiers given the context... examples: + - interface methods can only be public + - abstract methods can only be defined by abstract classes + - collisions... 2 methods with identical vmSelectors + - multiple methods with the same message pattern but different return types + - ambiguous, invisible or missing return/argument/exception types + - check the type of any array is not void + - check that each exception type is Throwable or a subclass of it +*/ +private void computeInheritedMethods() { + this.inheritedMethods = new HashtableOfObject(51); // maps method selectors to an array of methods... must search to match paramaters & return type + ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][]; + int lastPosition = 0; + interfacesToVisit[lastPosition] = type.superInterfaces(); + + ReferenceBinding superType; + if (this.type.isClass()) { + superType = this.type.superclass(); + } else { // check interface methods against Object + superType = this.type.scope.getJavaLangObject(); + } + MethodBinding[] nonVisibleDefaultMethods = null; + int nonVisibleCount = 0; + + while (superType != null) { + if (superType.isValidBinding()) { + ReferenceBinding[] itsInterfaces = superType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + + MethodBinding[] methods = superType.methods(); + nextMethod : for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (!(method.isPrivate() || method.isConstructor() || method.isDefaultAbstract())) { // look at all methods which are NOT private or constructors or default abstract + MethodBinding[] existingMethods = (MethodBinding[]) this.inheritedMethods.get(method.selector); + if (existingMethods != null) + for (int i = 0, length = existingMethods.length; i < length; i++) + if (method.returnType == existingMethods[i].returnType) + if (method.areParametersEqual(existingMethods[i])) + continue nextMethod; + if (nonVisibleDefaultMethods != null) + for (int i = 0; i < nonVisibleCount; i++) + if (method.returnType == nonVisibleDefaultMethods[i].returnType) + if (CharOperation.equals(method.selector, nonVisibleDefaultMethods[i].selector)) + if (method.areParametersEqual(nonVisibleDefaultMethods[i])) + continue nextMethod; + + if (!(method.isDefault() && (method.declaringClass.fPackage != type.fPackage))) { // ignore methods which have default visibility and are NOT defined in another package + if (existingMethods == null) + existingMethods = new MethodBinding[1]; + else + System.arraycopy(existingMethods, 0, + (existingMethods = new MethodBinding[existingMethods.length + 1]), 0, existingMethods.length - 1); + existingMethods[existingMethods.length - 1] = method; + this.inheritedMethods.put(method.selector, existingMethods); + } else { + if (nonVisibleDefaultMethods == null) + nonVisibleDefaultMethods = new MethodBinding[10]; + else if (nonVisibleCount == nonVisibleDefaultMethods.length) + System.arraycopy(nonVisibleDefaultMethods, 0, + (nonVisibleDefaultMethods = new MethodBinding[nonVisibleCount * 2]), 0, nonVisibleCount); + nonVisibleDefaultMethods[nonVisibleCount++] = method; + + if (method.isAbstract() && !this.type.isAbstract()) // non visible abstract methods cannot be overridden so the type must be defined abstract + this.problemReporter().abstractMethodCannotBeOverridden(this.type, method); + + MethodBinding[] current = (MethodBinding[]) this.currentMethods.get(method.selector); + if (current != null) { // non visible methods cannot be overridden so a warning is issued + foundMatch : for (int i = 0, length = current.length; i < length; i++) { + if (method.returnType == current[i].returnType) { + if (method.areParametersEqual(current[i])) { + this.problemReporter().overridesPackageDefaultMethod(current[i], method); + break foundMatch; + } + } + } + } + } + } + } + superType = superType.superclass(); + } + } + + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) { + superType = interfaces[j]; + if ((superType.tagBits & InterfaceVisited) == 0) { + superType.tagBits |= InterfaceVisited; + if (superType.isValidBinding()) { + ReferenceBinding[] itsInterfaces = superType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + + MethodBinding[] methods = superType.methods(); + for (int m = methods.length; --m >= 0;) { // Interface methods are all abstract public + MethodBinding method = methods[m]; + MethodBinding[] existingMethods = (MethodBinding[]) this.inheritedMethods.get(method.selector); + if (existingMethods == null) + existingMethods = new MethodBinding[1]; + else + System.arraycopy(existingMethods, 0, + (existingMethods = new MethodBinding[existingMethods.length + 1]), 0, existingMethods.length - 1); + existingMethods[existingMethods.length - 1] = method; + this.inheritedMethods.put(method.selector, existingMethods); + } + } + } + } + } + + // bit reinitialization + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) + interfaces[j].tagBits &= ~InterfaceVisited; + } +} +/* +computeInheritedMethodMembers + + "8.4.6.4" + "Compute all of the members for the type that are inherited from its supertypes. + This includes: + All of the methods implemented in the supertype hierarchy that are not overridden. + PROBLEM: Currently we do not remove overridden methods in the interface hierarchy. + This could cause a non-existent exception error to be detected." + + | supertype allSuperinterfaces methodsSeen interfacesSeen | + inheritedMethodMembers := LookupTable new: 50. + allSuperinterfaces := OrderedCollection new. + + type isJavaClass ifTrue: [ + supertype := type. + methodsSeen := EsIdentitySet new: 20. + [(supertype := self superclassFor: supertype) == nil] whileFalse: [ + (supertype isBuilderClass or: [supertype isValidDescriptor]) ifTrue: [ + allSuperinterfaces addAll: (self superinterfacesFor: supertype). + supertype javaUserDefinedMethodsDo: [:method | + (method isJavaPrivate or: [method isJavaConstructor]) ifFalse: [ + (method isJavaDefault and: [method declaringClass package symbol ~= type package symbol]) ifFalse: [ + (methodsSeen includes: method selector) ifFalse: [ + methodsSeen add: method selector. + (inheritedMethodMembers + at: (self methodSignatureFor: method selector) + ifAbsentPut: [OrderedCollection new: 3]) + add: method]]]]]]]. + + allSuperinterfaces addAll: (self superinterfacesFor: type). + interfacesSeen := EsIdentitySet new: allSuperinterfaces size * 2. + [allSuperinterfaces notEmpty] whileTrue: [ + supertype := allSuperinterfaces removeFirst. + (interfacesSeen includes: supertype) ifFalse: [ + interfacesSeen add: supertype. + (supertype isBuilderClass or: [supertype isValidDescriptor]) ifTrue: [ + allSuperinterfaces addAll: (self superinterfacesFor: supertype). + supertype javaUserDefinedMethodsDo: [:method | "Interface methods are all abstract public." + (inheritedMethodMembers + at: (self methodSignatureFor: method selector) + ifAbsentPut: [OrderedCollection new: 3]) + add: method]]]] +*/ +private void computeMethods() { + MethodBinding[] methods = type.methods(); + int size = methods.length; + this.currentMethods = new HashtableOfObject(size == 0 ? 1 : size); // maps method selectors to an array of methods... must search to match paramaters & return type + for (int m = size; --m >= 0;) { + MethodBinding method = methods[m]; + if (!(method.isConstructor() || method.isDefaultAbstract())) { // keep all methods which are NOT constructors or default abstract + MethodBinding[] existingMethods = (MethodBinding[]) this.currentMethods.get(method.selector); + if (existingMethods == null) + existingMethods = new MethodBinding[1]; + else + System.arraycopy(existingMethods, 0, + (existingMethods = new MethodBinding[existingMethods.length + 1]), 0, existingMethods.length - 1); + existingMethods[existingMethods.length - 1] = method; + this.currentMethods.put(method.selector, existingMethods); + } + } +} +private ReferenceBinding errorException() { + if (errorException == null) + this.errorException = this.type.scope.getJavaLangError(); + return errorException; +} +private boolean isAsVisible(MethodBinding newMethod, MethodBinding inheritedMethod) { + if (inheritedMethod.modifiers == newMethod.modifiers) return true; + + if (newMethod.isPublic()) return true; // Covers everything + if (inheritedMethod.isPublic()) return false; + + if (newMethod.isProtected()) return true; + if (inheritedMethod.isProtected()) return false; + + return !newMethod.isPrivate(); // The inheritedMethod cannot be private since it would not be visible +} +private boolean isSameClassOrSubclassOf(ReferenceBinding testClass, ReferenceBinding superclass) { + do { + if (testClass == superclass) return true; + } while ((testClass = testClass.superclass()) != null); + return false; +} +private boolean mustImplementAbstractMethod(MethodBinding abstractMethod) { + // if the type's superclass is an abstract class, then all abstract methods must be implemented + // otherwise, skip it if the type's superclass must implement any of the inherited methods + ReferenceBinding superclass = this.type.superclass(); + ReferenceBinding declaringClass = abstractMethod.declaringClass; + if (declaringClass.isClass()) { + while (superclass.isAbstract() && superclass != declaringClass) + superclass = superclass.superclass(); // find the first concrete superclass or the abstract declaringClass + } else { + if (this.type.implementsInterface(declaringClass, false)) + return !this.type.isAbstract(); + while (superclass.isAbstract() && !superclass.implementsInterface(declaringClass, false)) + superclass = superclass.superclass(); // find the first concrete superclass or the superclass which implements the interface + } + return superclass.isAbstract(); // if it is a concrete class then we have already reported problem against it +} +private ProblemReporter problemReporter() { + return this.type.scope.problemReporter(); +} +private ProblemReporter problemReporter(MethodBinding currentMethod) { + ProblemReporter reporter = problemReporter(); + if (currentMethod.declaringClass == type) // only report against the currentMethod if its implemented by the type + reporter.referenceContext = currentMethod.sourceMethod(); + return reporter; +} +private ReferenceBinding runtimeException() { + if (runtimeException == null) + this.runtimeException = this.type.scope.getJavaLangRuntimeException(); + return runtimeException; +} +public void verify(SourceTypeBinding type) { + this.type = type; + this.computeMethods(); + this.computeInheritedMethods(); + this.checkMethods(); +} +private void zzFieldProblems() { +} +/* +Binding creation is responsible for reporting all problems with fields: + - all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations - final/volatile) + - plus invalid modifiers given the context (the verifier did not do this before) + - include initializers in the modifier checks even though bindings are not created + - collisions... 2 fields with same name + - interfaces cannot define initializers + - nested types cannot define static fields + - with the type of the field: + - void is not a valid type (or for an array) + - an ambiguous, invisible or missing type + +verifyFields + + | toSearch | + (toSearch := newClass fields) notEmpty ifTrue: [ + newClass fromJavaClassFile + ifTrue: [ + toSearch do: [:field | + field isJavaInitializer ifFalse: [ + self verifyFieldType: field]]] + ifFalse: [ + toSearch do: [:field | + field isJavaInitializer + ifTrue: [self verifyFieldInitializer: field] + ifFalse: [self verifyField: field]]]] + +verifyFieldInitializer: field + + type isJavaInterface + ifTrue: [ + problemSummary + reportVerificationProblem: #InterfacesCannotHaveInitializers + args: #() + severity: nil + forField: field] + ifFalse: [ + field isJavaStatic + ifTrue: [ + field modifiers == AccStatic ifFalse: [ + problemSummary + reportVerificationProblem: #IllegalModifierForStaticInitializer + args: #() + severity: nil + forField: field]] + ifFalse: [ + field modifiers == 0 ifFalse: [ + problemSummary + reportVerificationProblem: #IllegalModifierForInitializer + args: #() + severity: nil + forField: field]]] + +verifyField: field + + (field basicModifiers anyMask: AccAlternateModifierProblem | AccModifierProblem) ifTrue: [ + self reportModifierProblemsOnField: field]. + + field isJavaStatic ifTrue: [ + type isJavaStatic ifFalse: [ + (type isJavaNestedType and: [type isJavaClass]) ifTrue: [ + problemSummary + reportVerificationProblem: #NestedClassCannotHaveStaticField + args: #() + severity: nil + forField: field]]]. + + self verifyFieldType: field + +verifyFieldType: field + + | descriptor fieldType | + "8.3 (Class) 9.3 (Interface)" + "Optimize the base type case" + field typeIsBaseType + ifTrue: [ + field typeName = 'V' ifTrue: [ "$NON-NLS$" + problemSummary + reportVerificationProblem: #IllegalTypeForField + args: (Array with: JavaVoid) + severity: nil + forField: field]] + ifFalse: [ + descriptor := field asDescriptorIn: nameEnvironment. + (fieldType := descriptor type) isValidDescriptor + ifTrue: [ + (fieldType isArrayType and: [fieldType leafComponentType isVoidType]) ifTrue: [ + problemSummary + reportVerificationProblem: #InvalidArrayType + args: (Array with: fieldType javaReadableName) + severity: nil + forField: field]] + ifFalse: [ + problemSummary + reportVerificationProblem: #UnboundTypeForField + args: (Array with: fieldType javaReadableName with: fieldType leafComponentType) + severity: nil + forField: field]]. + +reportModifierProblemsOnField: field + + (field basicModifiers anyMask: AccAlternateModifierProblem) ifTrue: [ + (field basicModifiers anyMask: AccModifierProblem) + ifTrue: [ + ^problemSummary + reportVerificationProblem: #OnlyOneVisibilityModifierAllowed + args: #() + severity: ErrorInfo::ConflictingModifier + forField: field] + ifFalse: [ + ^problemSummary + reportVerificationProblem: #DuplicateModifier + args: #() + severity: ErrorInfo::ConflictingModifier + forField: field]]. + + type isJavaInterface ifTrue: [ + ^problemSummary + reportVerificationProblem: #IllegalModifierForInterfaceField + args: #() + severity: nil + forField: field]. + + (field basicModifiers allMask: AccFinal | AccVolatile) ifTrue: [ + ^problemSummary + reportVerificationProblem: #IllegalModifierCombinationFinalVolatile + args: #() + severity: nil + forField: field]. + + ^problemSummary + reportVerificationProblem: #IllegalModifierForField + args: #() + severity: nil + forField: field + +void reportModifierProblems(FieldBinding field) { + if (field.isFinal() && field.isVolatile()) + this.problemReporter.illegalModifierCombinationFinalVolatile(field); + + // Should be able to detect all 3 problems NOT just 1 + if ((type.modifiers() & Modifiers.AccAlternateModifierProblem) == 0) { + if (this.type.isInterface()) + this.problemReporter.illegalModifierForInterfaceField(field); + else + this.problemReporter.illegalModifier(field); + } else { + if ((field.modifiers & Modifiers.AccModifierProblem) != 0) + this.problemReporter.onlyOneVisibilityModifierAllowed(field); + else + this.problemReporter.duplicateModifier(field); + } +} +*/ +private void zzImportProblems() { +} +/* +Binding creation is responsible for reporting all problems with imports: + - on demand imports which refer to missing packages + - with single type imports: + - resolves to an ambiguous, invisible or missing type + - conflicts with the type's source name + - has the same simple name as another import + +Note: VAJ ignored duplicate imports (only one was kept) + +verifyImports + + | importsBySimpleName nameEnvClass imports cl first | + importsBySimpleName := LookupTable new. + nameEnvClass := nameEnvironment class. + + "7.5.2" + type imports do: [:import | + import isOnDemand + ifTrue: [ + (nameEnvClass doesPackageExistNamed: import javaPackageName) ifFalse: [ + (nameEnvClass findJavaClassNamedFrom: import javaPackageName) == nil ifTrue: [ + problemSummary + reportVerificationProblem: #OnDemandImportRefersToMissingPackage + args: (Array with: import asString) + severity: ErrorInfo::ImportVerification + forType: type]]] + ifFalse: [ + (imports := importsBySimpleName at: import javaSimpleName ifAbsent: []) == nil + ifTrue: [ + importsBySimpleName at: import javaSimpleName put: (Array with: import)] + ifFalse: [ + (imports includes: import) ifFalse: [ + importsBySimpleName at: import javaSimpleName put: imports, (Array with: import)]]. + + "Ignore any imports which are simple names - we will treat these as no-ops." + + import javaPackageName notEmpty ifTrue: [ + cl := nameEnvClass findJavaClassNamedFrom: import asString. + + (cl ~~ nil and: [cl isJavaPublic or: [cl controller symbol == type controller symbol]]) ifFalse: [ + problemSummary + reportVerificationProblem: #SingleTypeImportRefersToInvisibleType + args: (Array with: import asString) + severity: ErrorInfo::ImportVerification + forType: type]]]]. + + importsBySimpleName notEmpty ifTrue: [ + importsBySimpleName keysAndValuesDo: [:simpleName :matching | + matching size == 1 + ifTrue: [ + simpleName = type sourceName ifTrue: [ + matching first javaReadableName = type javaReadableName ifFalse: [ + problemSummary + reportVerificationProblem: #SingleTypeImportConflictsWithType + args: #() + severity: nil + forType: type]]] + ifFalse: [ + problemSummary + reportVerificationProblem: #SingleTypeImportsHaveSameSimpleName + args: (Array with: simpleName) + severity: nil + forType: type]]] +*/ +private void zzTypeProblems() { +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/NestedTypeBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/NestedTypeBinding.java new file mode 100644 index 0000000..bdd9d60 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/NestedTypeBinding.java @@ -0,0 +1,202 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +public class NestedTypeBinding extends SourceTypeBinding { + public SourceTypeBinding enclosingType; + + public SyntheticArgumentBinding[] enclosingInstances; + public SyntheticArgumentBinding[] outerLocalVariables; + public int syntheticArgumentsOffset; // amount of slots used by synthetic constructor arguments +public NestedTypeBinding(char[][] typeName, ClassScope scope, SourceTypeBinding enclosingType) { + super(typeName, enclosingType.fPackage, scope); + this.tagBits |= IsNestedType; + this.enclosingType = enclosingType; +} +/* Add a new synthetic argument for . +* Answer the new argument or the existing argument if one already existed. +*/ + +public SyntheticArgumentBinding addSyntheticArgument(LocalVariableBinding actualOuterLocalVariable) { + SyntheticArgumentBinding synthLocal = null; + + if (outerLocalVariables == null) { + synthLocal = new SyntheticArgumentBinding(actualOuterLocalVariable); + outerLocalVariables = new SyntheticArgumentBinding[] {synthLocal}; + } else { + int size = outerLocalVariables.length; + int newArgIndex = size; + for (int i = size; --i >= 0;) { // must search backwards + if (outerLocalVariables[i].actualOuterLocalVariable == actualOuterLocalVariable) + return outerLocalVariables[i]; // already exists + if (outerLocalVariables[i].id > actualOuterLocalVariable.id) + newArgIndex = i; + } + SyntheticArgumentBinding[] synthLocals = new SyntheticArgumentBinding[size + 1]; + System.arraycopy(outerLocalVariables, 0, synthLocals, 0, newArgIndex); + synthLocals[newArgIndex] = synthLocal = new SyntheticArgumentBinding(actualOuterLocalVariable); + System.arraycopy(outerLocalVariables, newArgIndex, synthLocals, newArgIndex + 1, size - newArgIndex); + outerLocalVariables = synthLocals; + } + //System.out.println("Adding synth arg for local var: " + new String(actualOuterLocalVariable.name) + " to: " + new String(this.readableName())); + if (scope.referenceCompilationUnit().isPropagatingInnerClassEmulation) + this.updateInnerEmulationDependents(); + return synthLocal; +} +/* Add a new synthetic argument for . +* Answer the new argument or the existing argument if one already existed. +*/ + +public SyntheticArgumentBinding addSyntheticArgument(ReferenceBinding enclosingType) { + SyntheticArgumentBinding synthLocal = null; + if (enclosingInstances == null) { + synthLocal = new SyntheticArgumentBinding(enclosingType); + enclosingInstances = new SyntheticArgumentBinding[] {synthLocal}; + } else { + int size = enclosingInstances.length; + int newArgIndex = size; + for (int i = size; --i >= 0;) { + if (enclosingInstances[i].type == enclosingType) + return enclosingInstances[i]; // already exists + if (this.enclosingType() == enclosingType) + newArgIndex = 0; + } + SyntheticArgumentBinding[] newInstances = new SyntheticArgumentBinding[size + 1]; + System.arraycopy(enclosingInstances, 0, newInstances, newArgIndex == 0 ? 1 : 0, size); + newInstances[newArgIndex] = synthLocal = new SyntheticArgumentBinding(enclosingType); + enclosingInstances = newInstances; + } + //System.out.println("Adding synth arg for enclosing type: " + new String(enclosingType.readableName()) + " to: " + new String(this.readableName())); + if (scope.referenceCompilationUnit().isPropagatingInnerClassEmulation) + this.updateInnerEmulationDependents(); + return synthLocal; +} +/* Add a new synthetic argument and field for . +* Answer the new argument or the existing argument if one already existed. +*/ + +public SyntheticArgumentBinding addSyntheticArgumentAndField(LocalVariableBinding actualOuterLocalVariable) { + SyntheticArgumentBinding synthLocal = addSyntheticArgument(actualOuterLocalVariable); + if (synthLocal == null) return null; + + if (synthLocal.matchingField == null) + synthLocal.matchingField = addSyntheticField(actualOuterLocalVariable); + return synthLocal; +} +/* Add a new synthetic argument and field for . +* Answer the new argument or the existing argument if one already existed. +*/ + +public SyntheticArgumentBinding addSyntheticArgumentAndField(ReferenceBinding enclosingType) { + SyntheticArgumentBinding synthLocal = addSyntheticArgument(enclosingType); + if (synthLocal == null) return null; + + if (synthLocal.matchingField == null) + synthLocal.matchingField = addSyntheticField(enclosingType); + return synthLocal; +} +/** + * Compute the resolved positions for all the synthetic arguments + */ +final public void computeSyntheticArgumentsOffset() { + + int position = 1; // inside constructor, reserve room for receiver + + // insert enclosing instances first, followed by the outerLocals + SyntheticArgumentBinding[] enclosingInstances = this.syntheticEnclosingInstances(); + int enclosingInstancesCount = enclosingInstances == null ? 0 : enclosingInstances.length; + for (int i = 0; i < enclosingInstancesCount; i++){ + SyntheticArgumentBinding syntheticArg = enclosingInstances[i]; + syntheticArg.resolvedPosition = position; + if ((syntheticArg.type == LongBinding) || (syntheticArg.type == DoubleBinding)){ + position += 2; + } else { + position ++; + } + } + SyntheticArgumentBinding[] outerLocals = this.syntheticOuterLocalVariables(); + int outerLocalsCount = outerLocals == null ? 0 : outerLocals.length; + for (int i = 0; i < outerLocalsCount; i++){ + SyntheticArgumentBinding syntheticArg = outerLocals[i]; + syntheticArg.resolvedPosition = position; + if ((syntheticArg.type == LongBinding) || (syntheticArg.type == DoubleBinding)){ + position += 2; + } else { + position ++; + } + } + this.syntheticArgumentsOffset = position; +} +/* Answer the receiver's enclosing type... null if the receiver is a top level type. +*/ + +public ReferenceBinding enclosingType() { + return enclosingType; +} +/* Answer the synthetic argument for or null if one does not exist. +*/ + +public SyntheticArgumentBinding getSyntheticArgument(LocalVariableBinding actualOuterLocalVariable) { + if (outerLocalVariables == null) return null; // is null if no outer local variables are known + + for (int i = outerLocalVariables.length; --i >= 0;) + if (outerLocalVariables[i].actualOuterLocalVariable == actualOuterLocalVariable) + return outerLocalVariables[i]; + return null; +} +public SyntheticArgumentBinding[] syntheticEnclosingInstances() { + return enclosingInstances; // is null if no enclosing instances are required +} +public ReferenceBinding[] syntheticEnclosingInstanceTypes() { + if (enclosingInstances == null) + return null; + + int length = enclosingInstances.length; + ReferenceBinding types[] = new ReferenceBinding[length]; + for (int i = 0; i < length; i++) + types[i] = (ReferenceBinding) enclosingInstances[i].type; + return types; +} +public SyntheticArgumentBinding[] syntheticOuterLocalVariables() { + return outerLocalVariables; // is null if no enclosing instances are required +} +/* + * Trigger the dependency mechanism forcing the innerclass emulation + * to be propagated to all dependent source types. + */ +public void updateInnerEmulationDependents() { + // nothing to do in general, only local types are doing anything +} + +/* Answer the synthetic argument for or null if one does not exist. +*/ + +public SyntheticArgumentBinding getSyntheticArgument(ReferenceBinding targetEnclosingType, BlockScope scope, boolean onlyExactMatch) { + if (enclosingInstances == null) return null; // is null if no enclosing instances are known + + // exact match + for (int i = enclosingInstances.length; --i >= 0;) + if (enclosingInstances[i].type == targetEnclosingType) + if (enclosingInstances[i].actualOuterLocalVariable == null) + return enclosingInstances[i]; + + // type compatibility : to handle cases such as + // class T { class M{}} + // class S extends T { class N extends M {}} --> need to use S as a default enclosing instance for the super constructor call in N(). + if (!onlyExactMatch){ + for (int i = enclosingInstances.length; --i >= 0;) + if (enclosingInstances[i].actualOuterLocalVariable == null) + if (targetEnclosingType.isSuperclassOf((ReferenceBinding) enclosingInstances[i].type)) + return enclosingInstances[i]; + } + return null; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/PackageBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/PackageBinding.java new file mode 100644 index 0000000..4948914 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/PackageBinding.java @@ -0,0 +1,205 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; +import net.sourceforge.phpdt.internal.compiler.util.HashtableOfPackage; +import net.sourceforge.phpdt.internal.compiler.util.HashtableOfType; + +public class PackageBinding extends Binding implements TypeConstants { + public char[][] compoundName; + PackageBinding parent; + LookupEnvironment environment; + HashtableOfType knownTypes; + HashtableOfPackage knownPackages; +protected PackageBinding() { +} +public PackageBinding(char[][] compoundName, PackageBinding parent, LookupEnvironment environment) { + this.compoundName = compoundName; + this.parent = parent; + this.environment = environment; + this.knownTypes = null; // initialized if used... class counts can be very large 300-600 + this.knownPackages = new HashtableOfPackage(3); // sub-package counts are typically 0-3 +} +public PackageBinding(char[] topLevelPackageName, LookupEnvironment environment) { + this(new char[][] {topLevelPackageName}, null, environment); +} +/* Create the default package. +*/ + +public PackageBinding(LookupEnvironment environment) { + this(NoCharChar, null, environment); +} +private void addNotFoundPackage(char[] simpleName) { + knownPackages.put(simpleName, environment.theNotFoundPackage); +} +private void addNotFoundType(char[] simpleName) { + if (knownTypes == null) + knownTypes = new HashtableOfType(25); + knownTypes.put(simpleName, environment.theNotFoundType); +} +void addPackage(PackageBinding element) { + knownPackages.put(element.compoundName[element.compoundName.length - 1], element); +} +void addType(ReferenceBinding element) { + if (knownTypes == null) + knownTypes = new HashtableOfType(25); + knownTypes.put(element.compoundName[element.compoundName.length - 1], element); +} +/* API +* Answer the receiver's binding type from Binding.BindingID. +*/ + +public final int bindingType() { + return PACKAGE; +} +private PackageBinding findPackage(char[] name) { + if (!environment.isPackage(this.compoundName, name)) + return null; + + char[][] compoundName = CharOperation.arrayConcat(this.compoundName, name); + PackageBinding newPackageBinding = new PackageBinding(compoundName, this, environment); + addPackage(newPackageBinding); + return newPackageBinding; +} +/* Answer the subpackage named name; ask the oracle for the package if its not in the cache. +* Answer null if it could not be resolved. +* +* NOTE: This should only be used when we know there is NOT a type with the same name. +*/ + +PackageBinding getPackage(char[] name) { + PackageBinding binding = getPackage0(name); + if (binding != null) { + if (binding == environment.theNotFoundPackage) + return null; + else + return binding; + } + if ((binding = findPackage(name)) != null) + return binding; + + // not found so remember a problem package binding in the cache for future lookups + addNotFoundPackage(name); + return null; +} +/* Answer the subpackage named name if it exists in the cache. +* Answer theNotFoundPackage if it could not be resolved the first time +* it was looked up, otherwise answer null. +* +* NOTE: Senders must convert theNotFoundPackage into a real problem +* package if its to returned. +*/ + +PackageBinding getPackage0(char[] name) { + return knownPackages.get(name); +} +/* Answer the type named name; ask the oracle for the type if its not in the cache. +* Answer a NotVisible problem type if the type is not visible from the invocationPackage. +* Answer null if it could not be resolved. +* +* NOTE: This should only be used by source types/scopes which know there is NOT a +* package with the same name. +*/ + +ReferenceBinding getType(char[] name) { + ReferenceBinding binding = getType0(name); + if (binding == null) { + if ((binding = environment.askForType(this, name)) == null) { + // not found so remember a problem type binding in the cache for future lookups + addNotFoundType(name); + return null; + } + } + + if (binding == environment.theNotFoundType) + return null; + if (binding instanceof UnresolvedReferenceBinding) + binding = ((UnresolvedReferenceBinding) binding).resolve(environment); + if (binding.isNestedType()) + return new ProblemReferenceBinding(name, InternalNameProvided); + return binding; +} +/* Answer the type named name if it exists in the cache. +* Answer theNotFoundType if it could not be resolved the first time +* it was looked up, otherwise answer null. +* +* NOTE: Senders must convert theNotFoundType into a real problem +* reference type if its to returned. +*/ + +ReferenceBinding getType0(char[] name) { + if (knownTypes == null) + return null; + return knownTypes.get(name); +} +/* Answer the package or type named name; ask the oracle if it is not in the cache. +* Answer null if it could not be resolved. +* +* When collisions exist between a type name & a package name, answer the package. +* Treat the type as if it does not exist... a problem was already reported when the type was defined. +* +* NOTE: no visibility checks are performed. +* THIS SHOULD ONLY BE USED BY SOURCE TYPES/SCOPES. +*/ + +public Binding getTypeOrPackage(char[] name) { + PackageBinding packageBinding = getPackage0(name); + if (packageBinding != null && packageBinding != environment.theNotFoundPackage) + return packageBinding; + + ReferenceBinding typeBinding = getType0(name); + if (typeBinding != null && typeBinding != environment.theNotFoundType) { + if (typeBinding instanceof UnresolvedReferenceBinding) + typeBinding = ((UnresolvedReferenceBinding) typeBinding).resolve(environment); + if (typeBinding.isNestedType()) + return new ProblemReferenceBinding(name, InternalNameProvided); + return typeBinding; + } + + if (typeBinding == null && packageBinding == null) { + // find the package + if ((packageBinding = findPackage(name)) != null) + return packageBinding; + + // if no package was found, find the type named name relative to the receiver + if ((typeBinding = environment.askForType(this, name)) != null) { + if (typeBinding.isNestedType()) + return new ProblemReferenceBinding(name, InternalNameProvided); + return typeBinding; + } + + // Since name could not be found, add problem bindings + // to the collections so it will be reported as an error next time. + addNotFoundPackage(name); + addNotFoundType(name); + } else { + if (packageBinding == environment.theNotFoundPackage) + packageBinding = null; + if (typeBinding == environment.theNotFoundType) + typeBinding = null; + } + + if (packageBinding != null) + return packageBinding; + else + return typeBinding; +} +public char[] readableName() /*java.lang*/ { + return CharOperation.concatWith(compoundName, '.'); +} +public String toString() { + if (compoundName == NoCharChar) + return "The Default Package"; //$NON-NLS-1$ + else + return "package " + ((compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED"); //$NON-NLS-1$ //$NON-NLS-2$ +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ProblemBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ProblemBinding.java new file mode 100644 index 0000000..65befe8 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ProblemBinding.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class ProblemBinding extends Binding { + public char[] name; + public ReferenceBinding searchType; + private int problemId; +// NOTE: must only answer the subset of the name related to the problem + +public ProblemBinding(char[][] compoundName, int problemId) { + this(CharOperation.concatWith(compoundName, '.'), problemId); +} +// NOTE: must only answer the subset of the name related to the problem + +public ProblemBinding(char[][] compoundName, ReferenceBinding searchType, int problemId) { + this(CharOperation.concatWith(compoundName, '.'), searchType, problemId); +} +ProblemBinding(char[] name, int problemId) { + this.name = name; + this.problemId = problemId; +} +ProblemBinding(char[] name, ReferenceBinding searchType, int problemId) { + this(name, problemId); + this.searchType = searchType; +} +/* API +* Answer the receiver's binding type from Binding.BindingID. +*/ + +public final int bindingType() { + return VARIABLE | TYPE; +} +/* API +* Answer the problem id associated with the receiver. +* NoError if the receiver is a valid binding. +*/ + +public final int problemId() { + return problemId; +} +public char[] readableName() { + return name; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ProblemFieldBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ProblemFieldBinding.java new file mode 100644 index 0000000..540d5af --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ProblemFieldBinding.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class ProblemFieldBinding extends FieldBinding { + private int problemId; +// NOTE: must only answer the subset of the name related to the problem + +public ProblemFieldBinding(ReferenceBinding declaringClass, char[][] compoundName, int problemId) { + this(declaringClass, CharOperation.concatWith(compoundName, '.'), problemId); +} +public ProblemFieldBinding(ReferenceBinding declaringClass, char[] name, int problemId) { + this.declaringClass = declaringClass; + this.name = name; + this.problemId = problemId; +} +/* API +* Answer the problem id associated with the receiver. +* NoError if the receiver is a valid binding. +*/ + +public final int problemId() { + return problemId; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ProblemMethodBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ProblemMethodBinding.java new file mode 100644 index 0000000..4d6a9c5 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ProblemMethodBinding.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +public class ProblemMethodBinding extends MethodBinding { + private int problemId; + public MethodBinding closestMatch; +public ProblemMethodBinding(char[] selector, TypeBinding[] args, int problemId) { + this.selector = selector; + this.parameters = (args == null || args.length == 0) ? NoParameters : args; + this.problemId = problemId; +} +public ProblemMethodBinding(char[] selector, TypeBinding[] args, ReferenceBinding declaringClass, int problemId) { + this.selector = selector; + this.parameters = (args == null || args.length == 0) ? NoParameters : args; + this.declaringClass = declaringClass; + this.problemId = problemId; +} +public ProblemMethodBinding(MethodBinding closestMatch, char[] selector, TypeBinding[] args, int problemId) { + this(selector, args, problemId); + this.closestMatch = closestMatch; +} +/* API +* Answer the problem id associated with the receiver. +* NoError if the receiver is a valid binding. +*/ + +public final int problemId() { + return problemId; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ProblemPackageBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ProblemPackageBinding.java new file mode 100644 index 0000000..b83aaa2 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ProblemPackageBinding.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +public class ProblemPackageBinding extends PackageBinding { + private int problemId; +// NOTE: must only answer the subset of the name related to the problem + +ProblemPackageBinding(char[][] compoundName, int problemId) { + this.compoundName = compoundName; + this.problemId = problemId; +} +ProblemPackageBinding(char[] name, int problemId) { + this(new char[][] {name}, problemId); +} +/* API +* Answer the problem id associated with the receiver. +* NoError if the receiver is a valid binding. +*/ + +public final int problemId() { + return problemId; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ProblemReasons.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ProblemReasons.java new file mode 100644 index 0000000..fd83b60 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ProblemReasons.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +public interface ProblemReasons { + final int NoError = 0; + final int NotFound = 1; + final int NotVisible = 2; + final int Ambiguous = 3; + final int InternalNameProvided = 4; // used if an internal name is used in source + final int InheritedNameHidesEnclosingName = 5; + final int NonStaticReferenceInConstructorInvocation = 6; + final int NonStaticReferenceInStaticContext = 7; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ProblemReferenceBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ProblemReferenceBinding.java new file mode 100644 index 0000000..bde5823 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ProblemReferenceBinding.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +public class ProblemReferenceBinding extends ReferenceBinding { + public Binding original; + private int problemId; +// NOTE: must only answer the subset of the name related to the problem + +public ProblemReferenceBinding(char[][] compoundName, int problemId) { + this(compoundName, null, problemId); +} +public ProblemReferenceBinding(char[] name, int problemId) { + this(new char[][] {name}, null, problemId); +} + +public ProblemReferenceBinding(char[][] compoundName, Binding original, int problemId) { + this.compoundName = compoundName; + this.original = original; + this.problemId = problemId; +} +public ProblemReferenceBinding(char[] name, Binding original, int problemId) { + this(new char[][] {name}, original, problemId); +} +/* API +* Answer the problem id associated with the receiver. +* NoError if the receiver is a valid binding. +*/ + +public final int problemId() { + return problemId; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ReferenceBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ReferenceBinding.java new file mode 100644 index 0000000..d72bc99 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/ReferenceBinding.java @@ -0,0 +1,599 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.env.IDependent; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +/* +Not all fields defined by this type (& its subclasses) are initialized when it is created. +Some are initialized only when needed. + +Accessors have been provided for some public fields so all TypeBindings have the same API... +but access public fields directly whenever possible. +Non-public fields have accessors which should be used everywhere you expect the field to be initialized. + +null is NOT a valid value for a non-public field... it just means the field is not initialized. +*/ + +abstract public class ReferenceBinding extends TypeBinding implements IDependent { + public char[][] compoundName; + public char[] sourceName; + public int modifiers; + public PackageBinding fPackage; + + char[] fileName; + char[] constantPoolName; + char[] signature; + +public FieldBinding[] availableFields() { + return fields(); +} + +public MethodBinding[] availableMethods() { + return methods(); +} +/* Answer true if the receiver can be instantiated +*/ + +public boolean canBeInstantiated() { + return !(isAbstract() || isInterface()); +} +/* Answer true if the receiver is visible to the invocationPackage. +*/ + +public final boolean canBeSeenBy(PackageBinding invocationPackage) { + if (isPublic()) return true; + if (isPrivate()) return false; + + // isProtected() or isDefault() + return invocationPackage == fPackage; +} +/* Answer true if the receiver is visible to the receiverType and the invocationType. +*/ + +public final boolean canBeSeenBy(ReferenceBinding receiverType, SourceTypeBinding invocationType) { + if (isPublic()) return true; + + if (invocationType == this && invocationType == receiverType) return true; + + if (isProtected()) { + + // answer true if the invocationType is the declaringClass or they are in the same package + // OR the invocationType is a subclass of the declaringClass + // AND the invocationType is the invocationType or its subclass + // OR the type is a static method accessed directly through a type + // OR previous assertions are true for one of the enclosing type + if (invocationType == this) return true; + if (invocationType.fPackage == fPackage) return true; + + ReferenceBinding currentType = invocationType; + ReferenceBinding declaringClass = enclosingType(); // protected types always have an enclosing one + if (declaringClass == null) return false; // could be null if incorrect top-level protected type + //int depth = 0; + do { + if (declaringClass == invocationType) return true; + if (declaringClass.isSuperclassOf(currentType)) return true; + //depth++; + currentType = currentType.enclosingType(); + } while (currentType != null); + return false; + } + + if (isPrivate()) { + // answer true if the receiverType is the receiver or its enclosingType + // AND the invocationType and the receiver have a common enclosingType + if (!(receiverType == this || receiverType == enclosingType())) return false; + + if (invocationType != this) { + ReferenceBinding outerInvocationType = invocationType; + ReferenceBinding temp = outerInvocationType.enclosingType(); + while (temp != null) { + outerInvocationType = temp; + temp = temp.enclosingType(); + } + + ReferenceBinding outerDeclaringClass = this; + temp = outerDeclaringClass.enclosingType(); + while (temp != null) { + outerDeclaringClass = temp; + temp = temp.enclosingType(); + } + if (outerInvocationType != outerDeclaringClass) return false; + } + return true; + } + + // isDefault() + if (invocationType.fPackage != fPackage) return false; + + ReferenceBinding type = receiverType; + ReferenceBinding declaringClass = enclosingType() == null ? this : enclosingType(); + do { + if (declaringClass == type) return true; + if (fPackage != type.fPackage) return false; + } while ((type = type.superclass()) != null); + return false; +} +/* Answer true if the receiver is visible to the type provided by the scope. +* +* NOTE: Cannot invoke this method with a compilation unit scope. +*/ + +public final boolean canBeSeenBy(Scope scope) { + if (isPublic()) return true; + + SourceTypeBinding invocationType = scope.enclosingSourceType(); + if (invocationType == this) return true; + + if (isProtected()) { + // answer true if the receiver (or its enclosing type) is the superclass + // of the invocationType or in the same package + return invocationType.fPackage == fPackage + || isSuperclassOf(invocationType) + || enclosingType().isSuperclassOf(invocationType); // protected types always have an enclosing one + } + + if (isProtected()) { + // answer true if the invocationType is the declaringClass or they are in the same package + // OR the invocationType is a subclass of the declaringClass + // AND the invocationType is the invocationType or its subclass + // OR the type is a static method accessed directly through a type + // OR previous assertions are true for one of the enclosing type + if (invocationType.fPackage == fPackage) return true; + + ReferenceBinding currentType = invocationType; + ReferenceBinding declaringClass = enclosingType(); // protected types always have an enclosing one + if (declaringClass == null) return false; // could be null if incorrect top-level protected type + // int depth = 0; + do { + if (declaringClass == invocationType) return true; + if (declaringClass.isSuperclassOf(currentType)) return true; + // depth++; + currentType = currentType.enclosingType(); + } while (currentType != null); + return false; + } + if (isPrivate()) { + // answer true if the receiver and the invocationType have a common enclosingType + // already know they are not the identical type + ReferenceBinding outerInvocationType = invocationType; + ReferenceBinding temp = outerInvocationType.enclosingType(); + while (temp != null) { + outerInvocationType = temp; + temp = temp.enclosingType(); + } + + ReferenceBinding outerDeclaringClass = this; + temp = outerDeclaringClass.enclosingType(); + while (temp != null) { + outerDeclaringClass = temp; + temp = temp.enclosingType(); + } + return outerInvocationType == outerDeclaringClass; + } + + // isDefault() + return invocationType.fPackage == fPackage; +} +public void computeId() { + if (compoundName.length != 3) { + if (compoundName.length == 4 && CharOperation.equals(JAVA_LANG_REFLECT_CONSTRUCTOR, compoundName)) { + id = T_JavaLangReflectConstructor; + return; + } + return; // all other types are in java.*.* + } + + if (!CharOperation.equals(JAVA, compoundName[0])) + return; // assumes we only look up types in java + + if (!CharOperation.equals(LANG, compoundName[1])) { + if (CharOperation.equals(JAVA_IO_PRINTSTREAM, compoundName)) { + id = T_JavaIoPrintStream; + return; + } + return; // all other types are in java.lang + } + + if (CharOperation.equals(JAVA_LANG_OBJECT, compoundName)) { + id = T_JavaLangObject; + return; + } + if (CharOperation.equals(JAVA_LANG_STRING, compoundName)) { + id = T_JavaLangString; + return; + } + + // well-known exception types + if (CharOperation.equals(JAVA_LANG_THROWABLE, compoundName)) { + id = T_JavaLangThrowable; + return; + } + if (CharOperation.equals(JAVA_LANG_ERROR, compoundName)) { + id = T_JavaLangError; + return; + } + if (CharOperation.equals(JAVA_LANG_EXCEPTION, compoundName)) { + id = T_JavaLangException; + return; + } + if (CharOperation.equals(JAVA_LANG_CLASSNOTFOUNDEXCEPTION, compoundName)) { + id = T_JavaLangClassNotFoundException; + return; + } + if (CharOperation.equals(JAVA_LANG_NOCLASSDEFERROR, compoundName)) { + id = T_JavaLangNoClassDefError; + return; + } + + // other well-known types + if (CharOperation.equals(JAVA_LANG_CLASS, compoundName)) { + id = T_JavaLangClass; + return; + } + if (CharOperation.equals(JAVA_LANG_STRINGBUFFER, compoundName)) { + id = T_JavaLangStringBuffer; + return; + } + if (CharOperation.equals(JAVA_LANG_SYSTEM, compoundName)) { + id = T_JavaLangSystem; + return; + } + + if (CharOperation.equals(JAVA_LANG_INTEGER, compoundName)) { + id = T_JavaLangInteger; + return; + } + + if (CharOperation.equals(JAVA_LANG_BYTE, compoundName)) { + id = T_JavaLangByte; + return; + } + + if (CharOperation.equals(JAVA_LANG_CHARACTER, compoundName)) { + id = T_JavaLangCharacter; + return; + } + + if (CharOperation.equals(JAVA_LANG_FLOAT, compoundName)) { + id = T_JavaLangFloat; + return; + } + + if (CharOperation.equals(JAVA_LANG_DOUBLE, compoundName)) { + id = T_JavaLangDouble; + return; + } + + if (CharOperation.equals(JAVA_LANG_BOOLEAN, compoundName)) { + id = T_JavaLangBoolean; + return; + } + + if (CharOperation.equals(JAVA_LANG_SHORT, compoundName)) { + id = T_JavaLangShort; + return; + } + + if (CharOperation.equals(JAVA_LANG_LONG, compoundName)) { + id = T_JavaLangLong; + return; + } + + if (CharOperation.equals(JAVA_LANG_VOID, compoundName)) { + id = T_JavaLangVoid; + return; + } + + if (CharOperation.equals(JAVA_LANG_ASSERTIONERROR, compoundName)) { + id = T_JavaLangAssertionError; + return; + } +} +/* Answer the receiver's constant pool name. +* +* NOTE: This method should only be used during/after code gen. +*/ + +public char[] constantPoolName() /* java/lang/Object */ { + if (constantPoolName != null) return constantPoolName; + return constantPoolName = CharOperation.concatWith(compoundName, '/'); +} +String debugName() { + return (compoundName != null) ? new String(readableName()) : "UNNAMED TYPE"; //$NON-NLS-1$ +} +public final int depth() { + int depth = 0; + ReferenceBinding current = this; + while ((current = current.enclosingType()) != null) + depth++; + return depth; +} +/* Answer the receiver's enclosing type... null if the receiver is a top level type. +*/ + +public ReferenceBinding enclosingType() { + return null; +} +public final ReferenceBinding enclosingTypeAt(int relativeDepth) { + ReferenceBinding current = this; + while (relativeDepth-- > 0 && current != null) + current = current.enclosingType(); + return current; +} +public int fieldCount() { + return fields().length; +} +public FieldBinding[] fields() { + return NoFields; +} +public final int getAccessFlags() { + return modifiers & AccJustFlag; +} +public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) { + return null; +} +public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes) { + return null; +} +public FieldBinding getField(char[] fieldName) { + return null; +} +/** + * Answer the file name which defines the type. + * + * The path part (optional) must be separated from the actual + * file proper name by a java.io.File.separator. + * + * The proper file name includes the suffix extension (e.g. ".java") + * + * e.g. "c:/com/ibm/compiler/java/api/Compiler.java" + */ + +public char[] getFileName() { + return fileName; +} +public ReferenceBinding getMemberType(char[] typeName) { + ReferenceBinding[] memberTypes = memberTypes(); + for (int i = memberTypes.length; --i >= 0;) + if (CharOperation.equals(memberTypes[i].sourceName, typeName)) + return memberTypes[i]; + return null; +} +public MethodBinding[] getMethods(char[] selector) { + return NoMethods; +} +public PackageBinding getPackage() { + return fPackage; +} +/* Answer true if the receiver implements anInterface or is identical to anInterface. +* If searchHierarchy is true, then also search the receiver's superclasses. +* +* NOTE: Assume that anInterface is an interface. +*/ + +public boolean implementsInterface(ReferenceBinding anInterface, boolean searchHierarchy) { + if (this == anInterface) + return true; + + ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][]; + int lastPosition = -1; + ReferenceBinding currentType = this; + do { + ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } while (searchHierarchy && (currentType = currentType.superclass()) != null); + + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) { + if ((currentType = interfaces[j]) == anInterface) + return true; + + ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } + } + return false; +} +// Internal method... assume its only sent to classes NOT interfaces + +boolean implementsMethod(MethodBinding method) { + ReferenceBinding type = this; + while (type != null) { + MethodBinding[] methods = type.getMethods(method.selector); + for (int i = methods.length; --i >= 0;) + if (methods[i].areParametersEqual(method)) + return true; + type = type.superclass(); + } + return false; +} +/* Answer true if the receiver is an abstract type +*/ + +public final boolean isAbstract() { + return (modifiers & AccAbstract) != 0; +} +public final boolean isAnonymousType() { + return (tagBits & IsAnonymousType) != 0; +} +public final boolean isBinaryBinding() { + return (tagBits & IsBinaryBinding) != 0; +} +public final boolean isClass() { + return (modifiers & AccInterface) == 0; +} +/* Answer true if the receiver type can be assigned to the argument type (right) +*/ + +boolean isCompatibleWith(TypeBinding right) { + if (right == this) + return true; + if (right.id == T_Object) + return true; + if (!(right instanceof ReferenceBinding)) + return false; + + ReferenceBinding referenceBinding = (ReferenceBinding) right; + if (referenceBinding.isInterface()) + return implementsInterface(referenceBinding, true); + if (isInterface()) // Explicit conversion from an interface to a class is not allowed + return false; + return referenceBinding.isSuperclassOf(this); +} +/* Answer true if the receiver has default visibility +*/ + +public final boolean isDefault() { + return (modifiers & (AccPublic | AccProtected | AccPrivate)) == 0; +} +/* Answer true if the receiver is a deprecated type +*/ + +public final boolean isDeprecated() { + return (modifiers & AccDeprecated) != 0; +} +/* Answer true if the receiver is final and cannot be subclassed +*/ + +public final boolean isFinal() { + return (modifiers & AccFinal) != 0; +} +public final boolean isInterface() { + return (modifiers & AccInterface) != 0; +} +public final boolean isLocalType() { + return (tagBits & IsLocalType) != 0; +} +public final boolean isMemberType() { + return (tagBits & IsMemberType) != 0; +} +public final boolean isNestedType() { + return (tagBits & IsNestedType) != 0; +} +/* Answer true if the receiver has private visibility +*/ + +public final boolean isPrivate() { + return (modifiers & AccPrivate) != 0; +} +/* Answer true if the receiver has protected visibility +*/ + +public final boolean isProtected() { + return (modifiers & AccProtected) != 0; +} +/* Answer true if the receiver has public visibility +*/ + +public final boolean isPublic() { + return (modifiers & AccPublic) != 0; +} +/* Answer true if the receiver is a static member type (or toplevel) + */ + +public final boolean isStatic() { + return (modifiers & (AccStatic | AccInterface)) != 0 || + (tagBits & IsNestedType) == 0; +} +/* Answer true if all float operations must adher to IEEE 754 float/double rules +*/ + +public final boolean isStrictfp() { + return (modifiers & AccStrictfp) != 0; +} +/* Answer true if the receiver is in the superclass hierarchy of aType +* +* NOTE: Object.isSuperclassOf(Object) -> false +*/ + +public boolean isSuperclassOf(ReferenceBinding type) { + do { + if (this == (type = type.superclass())) return true; + } while (type != null); + + return false; +} +/* Answer true if the receiver is deprecated (or any of its enclosing types) +*/ + +public final boolean isViewedAsDeprecated() { + return (modifiers & AccDeprecated) != 0 || + (modifiers & AccDeprecatedImplicitly) != 0; +} +public ReferenceBinding[] memberTypes() { + return NoMemberTypes; +} +public MethodBinding[] methods() { + return NoMethods; +} +/** +* Answer the source name for the type. +* In the case of member types, as the qualified name from its top level type. +* For example, for a member type N defined inside M & A: "A.M.N". +*/ + +public char[] qualifiedSourceName() { + if (isMemberType()) { + return CharOperation.concat(enclosingType().qualifiedSourceName(), sourceName(), '.'); + } else { + return sourceName(); + } +} +public char[] readableName() /*java.lang.Object*/ { + if (isMemberType()) + return CharOperation.concat(enclosingType().readableName(), sourceName, '.'); + else + return CharOperation.concatWith(compoundName, '.'); +} +/* Answer the receiver's signature. +* +* NOTE: This method should only be used during/after code gen. +*/ + +public char[] signature() /* Ljava/lang/Object; */ { + if (signature != null) + return signature; + + return signature = CharOperation.concat('L', constantPoolName(), ';'); +} +public char[] sourceName() { + return sourceName; +} +public ReferenceBinding superclass() { + return null; +} +public ReferenceBinding[] superInterfaces() { + return NoSuperInterfaces; +} +public ReferenceBinding[] syntheticEnclosingInstanceTypes() { + if (isStatic()) return null; + + ReferenceBinding enclosingType = enclosingType(); + if (enclosingType == null) + return null; + else + return new ReferenceBinding[] {enclosingType}; +} +public SyntheticArgumentBinding[] syntheticOuterLocalVariables() { + return null; // is null if no enclosing instances are required +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/Scope.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/Scope.java new file mode 100644 index 0000000..858d480 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/Scope.java @@ -0,0 +1,1262 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration; +import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions; +import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; +import net.sourceforge.phpdt.internal.compiler.util.ObjectVector; + +public abstract class Scope + implements + BaseTypes, + BindingIds, + CompilerModifiers, + ProblemReasons, + TagBits, + TypeConstants, + TypeIds { + + public Scope parent; + public int kind; + + public final static int BLOCK_SCOPE = 1; + public final static int METHOD_SCOPE = 2; + public final static int CLASS_SCOPE = 3; + public final static int COMPILATION_UNIT_SCOPE = 4; + protected Scope(int kind, Scope parent) { + this.kind = kind; + this.parent = parent; + } + + public abstract ProblemReporter problemReporter(); + + // Internal use only + protected final boolean areParametersAssignable(TypeBinding[] parameters, TypeBinding[] arguments) { + if (parameters == arguments) + return true; + + int length = parameters.length; + if (length != arguments.length) + return false; + + for (int i = 0; i < length; i++) + if (parameters[i] != arguments[i]) + if (!arguments[i].isCompatibleWith(parameters[i])) + return false; + return true; + } + + /* Answer true if the left type can be assigned to right + */ + public static boolean areTypesCompatible(TypeBinding left, TypeBinding right) { + return left.isCompatibleWith(right); + } + + /* Answer an int describing the relationship between the given types. + * + * NotRelated + * EqualOrMoreSpecific : left is compatible with right + * MoreGeneric : right is compatible with left + */ + public static int compareTypes(TypeBinding left, TypeBinding right) { + if (areTypesCompatible(left, right)) + return EqualOrMoreSpecific; + if (areTypesCompatible(right, left)) + return MoreGeneric; + return NotRelated; + } + + /* Answer an int describing the relationship between the given type and unchecked exceptions. + * + * NotRelated + * EqualOrMoreSpecific : type is known for sure to be an unchecked exception type + * MoreGeneric : type is a supertype of an actual unchecked exception type + */ + public int compareUncheckedException(ReferenceBinding type) { + int comparison = compareTypes(type, getJavaLangRuntimeException()); + if (comparison != 0) return comparison; + return compareTypes(type, getJavaLangError()); + } + + public final CompilationUnitScope compilationUnitScope() { + Scope lastScope = null; + Scope scope = this; + do { + lastScope = scope; + scope = scope.parent; + } while (scope != null); + return (CompilationUnitScope) lastScope; + } + + public ArrayBinding createArray(TypeBinding type, int dimension) { + if (type.isValidBinding()) + return environment().createArrayType(type, dimension); + else + return new ArrayBinding(type, dimension); + } + + /* Answer the receiver's enclosing source type. + */ + public final SourceTypeBinding enclosingSourceType() { + Scope scope = this; + do { + if (scope instanceof ClassScope) + return ((ClassScope) scope).referenceContext.binding; + scope = scope.parent; + } while (scope != null); + return null; + } + public final LookupEnvironment environment() { + Scope scope, unitScope = this; + while ((scope = unitScope.parent) != null) + unitScope = scope; + return ((CompilationUnitScope) unitScope).environment; + } + + // Internal use only + public ReferenceBinding findDirectMemberType(char[] typeName, ReferenceBinding enclosingType) { + if ((enclosingType.tagBits & HasNoMemberTypes) != 0) + return null; // know it has no member types (nor inherited member types) + + SourceTypeBinding enclosingSourceType = enclosingSourceType(); + compilationUnitScope().recordReference(enclosingType.compoundName, typeName); + ReferenceBinding memberType = enclosingType.getMemberType(typeName); + if (memberType != null) { + compilationUnitScope().recordTypeReference(memberType); // to record supertypes + if (enclosingSourceType == null + ? memberType.canBeSeenBy(getCurrentPackage()) + : memberType.canBeSeenBy(enclosingType, enclosingSourceType)) + return memberType; + else + return new ProblemReferenceBinding(typeName, memberType, NotVisible); + } + return null; + } + + // Internal use only + public MethodBinding findExactMethod( + ReferenceBinding receiverType, + char[] selector, + TypeBinding[] argumentTypes, + InvocationSite invocationSite) { + + compilationUnitScope().recordTypeReference(receiverType); + compilationUnitScope().recordTypeReferences(argumentTypes); + MethodBinding exactMethod = receiverType.getExactMethod(selector, argumentTypes); + if (exactMethod != null) { + compilationUnitScope().recordTypeReferences(exactMethod.thrownExceptions); + if (receiverType.isInterface() || exactMethod.canBeSeenBy(receiverType, invocationSite, this)) + return exactMethod; + } + return null; + } + + // Internal use only + /* Answer the field binding that corresponds to fieldName. + Start the lookup at the receiverType. + InvocationSite implements + isSuperAccess(); this is used to determine if the discovered field is visible. + Only fields defined by the receiverType or its supertypes are answered; + a field of an enclosing type will not be found using this API. + + If no visible field is discovered, null is answered. + */ + public FieldBinding findField(TypeBinding receiverType, char[] fieldName, InvocationSite invocationSite) { + if (receiverType.isBaseType()) return null; + if (receiverType.isArrayType()) { + if (CharOperation.equals(fieldName, LENGTH)) + return ArrayBinding.LengthField; + return null; + } + + compilationUnitScope().recordTypeReference(receiverType); + + ReferenceBinding currentType = (ReferenceBinding) receiverType; + if (!currentType.canBeSeenBy(this)) + return new ProblemFieldBinding(currentType, fieldName, NotVisible); + // *** Need a new problem id - TypeNotVisible? + + FieldBinding field = currentType.getField(fieldName); + if (field != null) { + if (field.canBeSeenBy(currentType, invocationSite, this)) + return field; + else + return new ProblemFieldBinding(field.declaringClass, fieldName, NotVisible); + } + // collect all superinterfaces of receiverType until the field is found in a supertype + ReferenceBinding[][] interfacesToVisit = null; + int lastPosition = -1; + FieldBinding visibleField = null; + boolean keepLooking = true; + boolean notVisible = false; + // we could hold onto the not visible field for extra error reporting + while (keepLooking) { + ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (interfacesToVisit == null) + interfacesToVisit = new ReferenceBinding[5][]; + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, + 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], + 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + if ((currentType = currentType.superclass()) == null) + break; + + if ((field = currentType.getField(fieldName)) != null) { + keepLooking = false; + if (field.canBeSeenBy(receiverType, invocationSite, this)) { + if (visibleField == null) + visibleField = field; + else + return new ProblemFieldBinding(visibleField.declaringClass, fieldName, Ambiguous); + } else { + notVisible = true; + } + } + } + + // walk all visible interfaces to find ambiguous references + if (interfacesToVisit != null) { + ProblemFieldBinding ambiguous = null; + done : for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) { + ReferenceBinding anInterface = interfaces[j]; + if ((anInterface.tagBits & InterfaceVisited) == 0) { + // if interface as not already been visited + anInterface.tagBits |= InterfaceVisited; + if ((field = anInterface.getField(fieldName)) != null) { + if (visibleField == null) { + visibleField = field; + } else { + ambiguous = new ProblemFieldBinding(visibleField.declaringClass, fieldName, Ambiguous); + break done; + } + } else { + ReferenceBinding[] itsInterfaces = anInterface.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, + 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], + 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } + } + } + } + + // bit reinitialization + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) + interfaces[j].tagBits &= ~InterfaceVisited; + } + if (ambiguous != null) + return ambiguous; + } + + if (visibleField != null) + return visibleField; + if (notVisible) + return new ProblemFieldBinding(currentType, fieldName, NotVisible); + return null; + } + + // Internal use only + public ReferenceBinding findMemberType(char[] typeName, ReferenceBinding enclosingType) { + if ((enclosingType.tagBits & HasNoMemberTypes) != 0) + return null; // know it has no member types (nor inherited member types) + + SourceTypeBinding enclosingSourceType = enclosingSourceType(); + PackageBinding currentPackage = getCurrentPackage(); + compilationUnitScope().recordReference(enclosingType.compoundName, typeName); + ReferenceBinding memberType = enclosingType.getMemberType(typeName); + if (memberType != null) { + compilationUnitScope().recordTypeReference(memberType); // to record supertypes + if (enclosingSourceType == null + ? memberType.canBeSeenBy(currentPackage) + : memberType.canBeSeenBy(enclosingType, enclosingSourceType)) + return memberType; + else + return new ProblemReferenceBinding(typeName, memberType, NotVisible); + } + + // collect all superinterfaces of receiverType until the memberType is found in a supertype + ReferenceBinding currentType = enclosingType; + ReferenceBinding[][] interfacesToVisit = null; + int lastPosition = -1; + ReferenceBinding visibleMemberType = null; + boolean keepLooking = true; + ReferenceBinding notVisible = null; + // we could hold onto the not visible field for extra error reporting + while (keepLooking) { + ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (interfacesToVisit == null) + interfacesToVisit = new ReferenceBinding[5][]; + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, + 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], + 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + if ((currentType = currentType.superclass()) == null) + break; + + compilationUnitScope().recordReference(currentType.compoundName, typeName); + if ((memberType = currentType.getMemberType(typeName)) != null) { + compilationUnitScope().recordTypeReference(memberType); // to record supertypes + keepLooking = false; + if (enclosingSourceType == null + ? memberType.canBeSeenBy(currentPackage) + : memberType.canBeSeenBy(enclosingType, enclosingSourceType)) { + if (visibleMemberType == null) + visibleMemberType = memberType; + else + return new ProblemReferenceBinding(typeName, Ambiguous); + } else { + notVisible = memberType; + } + } + } + // walk all visible interfaces to find ambiguous references + if (interfacesToVisit != null) { + ProblemReferenceBinding ambiguous = null; + done : for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) { + ReferenceBinding anInterface = interfaces[j]; + if ((anInterface.tagBits & InterfaceVisited) == 0) { + // if interface as not already been visited + anInterface.tagBits |= InterfaceVisited; + compilationUnitScope().recordReference(anInterface.compoundName, typeName); + if ((memberType = anInterface.getMemberType(typeName)) != null) { + compilationUnitScope().recordTypeReference(memberType); // to record supertypes + if (visibleMemberType == null) { + visibleMemberType = memberType; + } else { + ambiguous = new ProblemReferenceBinding(typeName, Ambiguous); + break done; + } + } else { + ReferenceBinding[] itsInterfaces = anInterface.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, + 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], + 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } + } + } + } + + // bit reinitialization + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) + interfaces[j].tagBits &= ~InterfaceVisited; + } + if (ambiguous != null) + return ambiguous; + } + if (visibleMemberType != null) + return visibleMemberType; + if (notVisible != null) + return new ProblemReferenceBinding(typeName, notVisible, NotVisible); + return null; + } + + // Internal use only + public MethodBinding findMethod( + ReferenceBinding receiverType, + char[] selector, + TypeBinding[] argumentTypes, + InvocationSite invocationSite) { + + ReferenceBinding currentType = receiverType; + MethodBinding matchingMethod = null; + ObjectVector found = new ObjectVector(); + + compilationUnitScope().recordTypeReference(receiverType); + compilationUnitScope().recordTypeReferences(argumentTypes); + + if (currentType.isInterface()) { + MethodBinding[] currentMethods = currentType.getMethods(selector); + int currentLength = currentMethods.length; + if (currentLength == 1) { + matchingMethod = currentMethods[0]; + } else if (currentLength > 1) { + found.addAll(currentMethods); + } + matchingMethod = findMethodInSuperInterfaces(currentType, selector, found, matchingMethod); + currentType = getJavaLangObject(); + } + + // superclass lookup + ReferenceBinding classHierarchyStart = currentType; + while (currentType != null) { + MethodBinding[] currentMethods = currentType.getMethods(selector); + int currentLength = currentMethods.length; + if (currentLength == 1 && matchingMethod == null && found.size == 0) { + matchingMethod = currentMethods[0]; + } else if (currentLength > 0) { + if (matchingMethod != null) { + found.add(matchingMethod); + matchingMethod = null; + } + found.addAll(currentMethods); + } + currentType = currentType.superclass(); + } + + int foundSize = found.size; + if (foundSize == 0) { + if (matchingMethod != null && areParametersAssignable(matchingMethod.parameters, argumentTypes)) + return matchingMethod; + return findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, matchingMethod, found); + } + + MethodBinding[] candidates = new MethodBinding[foundSize]; + int candidatesCount = 0; + // argument type compatibility check + for (int i = 0; i < foundSize; i++) { + MethodBinding methodBinding = (MethodBinding) found.elementAt(i); + if (areParametersAssignable(methodBinding.parameters, argumentTypes)) + candidates[candidatesCount++] = methodBinding; + } + if (candidatesCount == 1) { + compilationUnitScope().recordTypeReferences(candidates[0].thrownExceptions); + return candidates[0]; // have not checked visibility + } + if (candidatesCount == 0) { // try to find a close match when the parameter order is wrong or missing some parameters + MethodBinding interfaceMethod = + findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, matchingMethod, found); + if (interfaceMethod != null) return interfaceMethod; + + int argLength = argumentTypes.length; + foundSize = found.size; + nextMethod : for (int i = 0; i < foundSize; i++) { + MethodBinding methodBinding = (MethodBinding) found.elementAt(i); + TypeBinding[] params = methodBinding.parameters; + int paramLength = params.length; + nextArg: for (int a = 0; a < argLength; a++) { + TypeBinding arg = argumentTypes[a]; + for (int p = 0; p < paramLength; p++) + if (params[p] == arg) + continue nextArg; + continue nextMethod; + } + return methodBinding; + } + return (MethodBinding) found.elementAt(0); // no good match so just use the first one found + } + + // visibility check + int visiblesCount = 0; + for (int i = 0; i < candidatesCount; i++) { + MethodBinding methodBinding = candidates[i]; + if (methodBinding.canBeSeenBy(receiverType, invocationSite, this)) { + if (visiblesCount != i) { + candidates[i] = null; + candidates[visiblesCount] = methodBinding; + } + visiblesCount++; + } + } + if (visiblesCount == 1) { + compilationUnitScope().recordTypeReferences(candidates[0].thrownExceptions); + return candidates[0]; + } + if (visiblesCount == 0) { + MethodBinding interfaceMethod = + findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, matchingMethod, found); + if (interfaceMethod != null) return interfaceMethod; + return new ProblemMethodBinding(candidates[0].selector, argumentTypes, candidates[0].declaringClass, NotVisible); + } + if (candidates[0].declaringClass.isClass()) { + return mostSpecificClassMethodBinding(candidates, visiblesCount); + } else { + return mostSpecificInterfaceMethodBinding(candidates, visiblesCount); + } + } + + // abstract method lookup lookup (since maybe missing default abstract methods) + public MethodBinding findDefaultAbstractMethod( + ReferenceBinding receiverType, + char[] selector, + TypeBinding[] argumentTypes, + InvocationSite invocationSite, + ReferenceBinding classHierarchyStart, + MethodBinding matchingMethod, + ObjectVector found) { + + int startFoundSize = found.size; + ReferenceBinding currentType = classHierarchyStart; + while (currentType != null) { + matchingMethod = findMethodInSuperInterfaces(currentType, selector, found, matchingMethod); + currentType = currentType.superclass(); + } + int foundSize = found.size; + if (foundSize == startFoundSize) return matchingMethod; // maybe null + + MethodBinding[] candidates = new MethodBinding[foundSize - startFoundSize]; + int candidatesCount = 0; + // argument type compatibility check + for (int i = startFoundSize; i < foundSize; i++) { + MethodBinding methodBinding = (MethodBinding) found.elementAt(i); + if (areParametersAssignable(methodBinding.parameters, argumentTypes)) + candidates[candidatesCount++] = methodBinding; + } + if (candidatesCount == 1) { + compilationUnitScope().recordTypeReferences(candidates[0].thrownExceptions); + return candidates[0]; + } + if (candidatesCount == 0) { // try to find a close match when the parameter order is wrong or missing some parameters + int argLength = argumentTypes.length; + nextMethod : for (int i = 0; i < foundSize; i++) { + MethodBinding methodBinding = (MethodBinding) found.elementAt(i); + TypeBinding[] params = methodBinding.parameters; + int paramLength = params.length; + nextArg: for (int a = 0; a < argLength; a++) { + TypeBinding arg = argumentTypes[a]; + for (int p = 0; p < paramLength; p++) + if (params[p] == arg) + continue nextArg; + continue nextMethod; + } + return methodBinding; + } + return (MethodBinding) found.elementAt(0); // no good match so just use the first one found + } + // no need to check for visibility - interface methods are public + return mostSpecificInterfaceMethodBinding(candidates, candidatesCount); + } + + public MethodBinding findMethodInSuperInterfaces( + ReferenceBinding currentType, + char[] selector, + ObjectVector found, + MethodBinding matchingMethod) { + + ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][]; + int lastPosition = -1; + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) { + currentType = interfaces[j]; + if ((currentType.tagBits & InterfaceVisited) == 0) { + // if interface as not already been visited + currentType.tagBits |= InterfaceVisited; + + MethodBinding[] currentMethods = currentType.getMethods(selector); + int currentLength = currentMethods.length; + if (currentLength == 1 && matchingMethod == null && found.size == 0) { + matchingMethod = currentMethods[0]; + } else if (currentLength > 0) { + if (matchingMethod != null) { + found.add(matchingMethod); + matchingMethod = null; + } + found.addAll(currentMethods); + } + itsInterfaces = currentType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } + } + } + + // bit reinitialization + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) + interfaces[j].tagBits &= ~InterfaceVisited; + } + } + return matchingMethod; + } + + // Internal use only + public MethodBinding findMethodForArray( + ArrayBinding receiverType, + char[] selector, + TypeBinding[] argumentTypes, + InvocationSite invocationSite) { + + ReferenceBinding object = getJavaLangObject(); + MethodBinding methodBinding = object.getExactMethod(selector, argumentTypes); + if (methodBinding != null) { + // handle the method clone() specially... cannot be protected or throw exceptions + if (argumentTypes == NoParameters && CharOperation.equals(selector, CLONE)) + return new MethodBinding( + (methodBinding.modifiers ^ AccProtected) | AccPublic, + CLONE, + methodBinding.returnType, + argumentTypes, + null, + object); + if (methodBinding.canBeSeenBy(receiverType, invocationSite, this)) + return methodBinding; + } + // answers closest approximation, may not check argumentTypes or visibility + methodBinding = findMethod(object, selector, argumentTypes, invocationSite); + if (methodBinding == null) + return new ProblemMethodBinding(selector, argumentTypes, NotFound); + if (methodBinding.isValidBinding()) { + if (!areParametersAssignable(methodBinding.parameters, argumentTypes)) + return new ProblemMethodBinding( + methodBinding, + selector, + argumentTypes, + NotFound); + if (!methodBinding.canBeSeenBy(receiverType, invocationSite, this)) + return new ProblemMethodBinding( + selector, + argumentTypes, + methodBinding.declaringClass, + NotVisible); + } + return methodBinding; + } + + // Internal use only + public ReferenceBinding findType( + char[] typeName, + PackageBinding declarationPackage, + PackageBinding invocationPackage) { + + compilationUnitScope().recordReference(declarationPackage.compoundName, typeName); + ReferenceBinding typeBinding = declarationPackage.getType(typeName); + if (typeBinding == null) + return null; + + if (typeBinding.isValidBinding()) { +// Not convinced that this is necessary +// compilationUnitScope().recordTypeReference(typeBinding); // to record supertypes + if (declarationPackage != invocationPackage && !typeBinding.canBeSeenBy(invocationPackage)) + return new ProblemReferenceBinding(typeName, typeBinding, NotVisible); + } + return typeBinding; + } + + public TypeBinding getBaseType(char[] name) { + // list should be optimized (with most often used first) + int length = name.length; + if (length > 2 && length < 8) { + switch (name[0]) { + case 'i' : + if (length == 3 && name[1] == 'n' && name[2] == 't') + return IntBinding; + break; + case 'v' : + if (length == 4 && name[1] == 'o' && name[2] == 'i' && name[3] == 'd') + return VoidBinding; + break; + case 'b' : + if (length == 7 + && name[1] == 'o' + && name[2] == 'o' + && name[3] == 'l' + && name[4] == 'e' + && name[5] == 'a' + && name[6] == 'n') + return BooleanBinding; + if (length == 4 && name[1] == 'y' && name[2] == 't' && name[3] == 'e') + return ByteBinding; + break; + case 'c' : + if (length == 4 && name[1] == 'h' && name[2] == 'a' && name[3] == 'r') + return CharBinding; + break; + case 'd' : + if (length == 6 + && name[1] == 'o' + && name[2] == 'u' + && name[3] == 'b' + && name[4] == 'l' + && name[5] == 'e') + return DoubleBinding; + break; + case 'f' : + if (length == 5 + && name[1] == 'l' + && name[2] == 'o' + && name[3] == 'a' + && name[4] == 't') + return FloatBinding; + break; + case 'l' : + if (length == 4 && name[1] == 'o' && name[2] == 'n' && name[3] == 'g') + return LongBinding; + break; + case 's' : + if (length == 5 + && name[1] == 'h' + && name[2] == 'o' + && name[3] == 'r' + && name[4] == 't') + return ShortBinding; + } + } + return null; + } + + public final PackageBinding getCurrentPackage() { + Scope scope, unitScope = this; + while ((scope = unitScope.parent) != null) + unitScope = scope; + return ((CompilationUnitScope) unitScope).fPackage; + } + + public final ReferenceBinding getJavaIoSerializable() { + compilationUnitScope().recordQualifiedReference(JAVA_IO_SERIALIZABLE); + ReferenceBinding type = environment().getType(JAVA_IO_SERIALIZABLE); + if (type != null) return type; + + problemReporter().isClassPathCorrect(JAVA_IO_SERIALIZABLE, referenceCompilationUnit()); + return null; // will not get here since the above error aborts the compilation + } + + public final ReferenceBinding getJavaLangClass() { + compilationUnitScope().recordQualifiedReference(JAVA_LANG_CLASS); + ReferenceBinding type = environment().getType(JAVA_LANG_CLASS); + if (type != null) return type; + + problemReporter().isClassPathCorrect(JAVA_LANG_CLASS, referenceCompilationUnit()); + return null; // will not get here since the above error aborts the compilation + } + + public final ReferenceBinding getJavaLangCloneable() { + compilationUnitScope().recordQualifiedReference(JAVA_LANG_CLONEABLE); + ReferenceBinding type = environment().getType(JAVA_LANG_CLONEABLE); + if (type != null) return type; + + problemReporter().isClassPathCorrect(JAVA_LANG_CLONEABLE, referenceCompilationUnit()); + return null; // will not get here since the above error aborts the compilation + } + + public final ReferenceBinding getJavaLangError() { + compilationUnitScope().recordQualifiedReference(JAVA_LANG_ERROR); + ReferenceBinding type = environment().getType(JAVA_LANG_ERROR); + if (type != null) return type; + + problemReporter().isClassPathCorrect(JAVA_LANG_ERROR, referenceCompilationUnit()); + return null; // will not get here since the above error aborts the compilation + } + + public final ReferenceBinding getJavaLangAssertionError() { + compilationUnitScope().recordQualifiedReference(JAVA_LANG_ASSERTIONERROR); + ReferenceBinding type = environment().getType(JAVA_LANG_ASSERTIONERROR); + if (type != null) return type; + problemReporter().isClassPathCorrect(JAVA_LANG_ASSERTIONERROR, referenceCompilationUnit()); + return null; // will not get here since the above error aborts the compilation + } + + public final ReferenceBinding getJavaLangObject() { + compilationUnitScope().recordQualifiedReference(JAVA_LANG_OBJECT); + ReferenceBinding type = environment().getType(JAVA_LANG_OBJECT); + if (type != null) return type; + + problemReporter().isClassPathCorrect(JAVA_LANG_OBJECT, referenceCompilationUnit()); + return null; // will not get here since the above error aborts the compilation + } + + public final ReferenceBinding getJavaLangRuntimeException() { + compilationUnitScope().recordQualifiedReference(JAVA_LANG_RUNTIMEEXCEPTION); + ReferenceBinding type = environment().getType(JAVA_LANG_RUNTIMEEXCEPTION); + if (type != null) return type; + + problemReporter().isClassPathCorrect(JAVA_LANG_RUNTIMEEXCEPTION, referenceCompilationUnit()); + return null; // will not get here since the above error aborts the compilation + } + + public final ReferenceBinding getJavaLangString() { + compilationUnitScope().recordQualifiedReference(JAVA_LANG_STRING); + ReferenceBinding type = environment().getType(JAVA_LANG_STRING); + if (type != null) return type; + + problemReporter().isClassPathCorrect(JAVA_LANG_STRING, referenceCompilationUnit()); + return null; // will not get here since the above error aborts the compilation + } + + public final ReferenceBinding getJavaLangThrowable() { + compilationUnitScope().recordQualifiedReference(JAVA_LANG_THROWABLE); + ReferenceBinding type = environment().getType(JAVA_LANG_THROWABLE); + if (type != null) return type; + + problemReporter().isClassPathCorrect(JAVA_LANG_THROWABLE, referenceCompilationUnit()); + return null; // will not get here since the above error aborts the compilation + } + + /* Answer the type binding corresponding to the typeName argument, relative to the enclosingType. + */ + public final ReferenceBinding getMemberType(char[] typeName, ReferenceBinding enclosingType) { + ReferenceBinding memberType = findMemberType(typeName, enclosingType); + if (memberType != null) return memberType; + return new ProblemReferenceBinding(typeName, NotFound); + } + + /* Answer the type binding corresponding to the compoundName. + * + * NOTE: If a problem binding is returned, senders should extract the compound name + * from the binding & not assume the problem applies to the entire compoundName. + */ + public final TypeBinding getType(char[][] compoundName) { + int typeNameLength = compoundName.length; + if (typeNameLength == 1) { + // Would like to remove this test and require senders to specially handle base types + TypeBinding binding = getBaseType(compoundName[0]); + if (binding != null) return binding; + } + + compilationUnitScope().recordQualifiedReference(compoundName); + Binding binding = + getTypeOrPackage(compoundName[0], typeNameLength == 1 ? TYPE : TYPE | PACKAGE); + if (binding == null) + return new ProblemReferenceBinding(compoundName[0], NotFound); + if (!binding.isValidBinding()) + return (ReferenceBinding) binding; + + int currentIndex = 1; + boolean checkVisibility = false; + if (binding instanceof PackageBinding) { + PackageBinding packageBinding = (PackageBinding) binding; + while (currentIndex < typeNameLength) { + binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]); // does not check visibility + if (binding == null) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + if (!binding.isValidBinding()) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + binding.problemId()); + if (!(binding instanceof PackageBinding)) + break; + packageBinding = (PackageBinding) binding; + } + if (binding instanceof PackageBinding) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + checkVisibility = true; + } + + // binding is now a ReferenceBinding + ReferenceBinding typeBinding = (ReferenceBinding) binding; + compilationUnitScope().recordTypeReference(typeBinding); // to record supertypes + if (checkVisibility) // handles the fall through case + if (!typeBinding.canBeSeenBy(this)) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + typeBinding, + NotVisible); + + while (currentIndex < typeNameLength) { + typeBinding = getMemberType(compoundName[currentIndex++], typeBinding); + if (!typeBinding.isValidBinding()) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + typeBinding.problemId()); + } + return typeBinding; + } + + /* Answer the type binding that corresponds the given name, starting the lookup in the receiver. + * The name provided is a simple source name (e.g., "Object" , "Point", ...) + */ + // The return type of this method could be ReferenceBinding if we did not answer base types. + // NOTE: We could support looking for Base Types last in the search, however any code using + // this feature would be extraordinarily slow. Therefore we don't do this + public final TypeBinding getType(char[] name) { + // Would like to remove this test and require senders to specially handle base types + TypeBinding binding = getBaseType(name); + if (binding != null) return binding; + return (ReferenceBinding) getTypeOrPackage(name, TYPE); + } + + // Added for code assist... NOT Public API + public final Binding getTypeOrPackage(char[][] compoundName) { + int nameLength = compoundName.length; + if (nameLength == 1) { + TypeBinding binding = getBaseType(compoundName[0]); + if (binding != null) return binding; + } + Binding binding = getTypeOrPackage(compoundName[0], TYPE | PACKAGE); + if (!binding.isValidBinding()) return binding; + + int currentIndex = 1; + boolean checkVisibility = false; + if (binding instanceof PackageBinding) { + PackageBinding packageBinding = (PackageBinding) binding; + + while (currentIndex < nameLength) { + binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]); + if (binding == null) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + if (!binding.isValidBinding()) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + binding.problemId()); + if (!(binding instanceof PackageBinding)) + break; + packageBinding = (PackageBinding) binding; + } + if (binding instanceof PackageBinding) return binding; + checkVisibility = true; + } + // binding is now a ReferenceBinding + ReferenceBinding typeBinding = (ReferenceBinding) binding; + if (checkVisibility) // handles the fall through case + if (!typeBinding.canBeSeenBy(this)) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + typeBinding, + NotVisible); + + while (currentIndex < nameLength) { + typeBinding = getMemberType(compoundName[currentIndex++], typeBinding); + // checks visibility + if (!typeBinding.isValidBinding()) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + typeBinding.problemId()); + } + return typeBinding; + } + + /* Internal use only + */ + final Binding getTypeOrPackage(char[] name, int mask) { + + Scope scope = this; + ReferenceBinding foundType = null; + if ((mask & TYPE) == 0) { + Scope next = scope; + while ((next = scope.parent) != null) + scope = next; + } else { + done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found + switch (scope.kind) { + case METHOD_SCOPE : + case BLOCK_SCOPE : + ReferenceBinding localType = ((BlockScope) scope).findLocalType(name); // looks in this scope only + if (localType != null) { + if (foundType != null && foundType != localType) + return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName); + return localType; + } + break; + case CLASS_SCOPE : + SourceTypeBinding sourceType = ((ClassScope) scope).referenceContext.binding; + if (CharOperation.equals(sourceType.sourceName, name)) { + if (foundType != null && foundType != sourceType) + return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName); + return sourceType; + } + + ReferenceBinding memberType = findMemberType(name, sourceType); + if (memberType != null) { // skip it if we did not find anything + if (memberType.problemId() == Ambiguous) { + if (foundType == null || foundType.problemId() == NotVisible) + // supercedes any potential InheritedNameHidesEnclosingName problem + return memberType; + else + // make the user qualify the type, likely wants the first inherited type + return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName); + } + if (memberType.isValidBinding()) { + if (sourceType == memberType.enclosingType() + || environment().options.complianceLevel >= CompilerOptions.JDK1_4) { + // found a valid type in the 'immediate' scope (ie. not inherited) + // OR in 1.4 mode (inherited shadows enclosing) + if (foundType == null) + return memberType; + if (foundType.isValidBinding()) + // if a valid type was found, complain when another is found in an 'immediate' enclosing type (ie. not inherited) + if (foundType != memberType) + return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName); + } + } + if (foundType == null || (foundType.problemId() == NotVisible && memberType.problemId() != NotVisible)) + // only remember the memberType if its the first one found or the previous one was not visible & memberType is... + foundType = memberType; + } + break; + case COMPILATION_UNIT_SCOPE : + break done; + } + scope = scope.parent; + } + if (foundType != null && foundType.problemId() != NotVisible) + return foundType; + } + + // at this point the scope is a compilation unit scope + CompilationUnitScope unitScope = (CompilationUnitScope) scope; + // ask for the imports + name + if ((mask & TYPE) != 0) { + // check single type imports. + ImportBinding[] imports = unitScope.imports; + if (imports != null){ + // copy the list, since single type imports are removed if they cannot be resolved + for (int i = 0, length = imports.length; i < length; i++) { + ImportBinding typeImport = imports[i]; + if (!typeImport.onDemand) + if (CharOperation.equals(typeImport.compoundName[typeImport.compoundName.length - 1], name)) + if (unitScope.resolveSingleTypeImport(typeImport) != null) { + if (typeImport.reference != null) typeImport.reference.used = true; + return typeImport.resolvedImport; // already know its visible + } + } + } + // check if the name is in the current package (answer the problem binding unless its not found in which case continue to look) + ReferenceBinding type = findType(name, unitScope.fPackage, unitScope.fPackage); // is always visible + if (type != null) return type; + + // check on demand imports + boolean foundInImport = false; + if (imports != null){ + for (int i = 0, length = imports.length; i < length; i++) { + ImportBinding someImport = imports[i]; + if (someImport.onDemand) { + Binding resolvedImport = someImport.resolvedImport; + ReferenceBinding temp = + (resolvedImport instanceof PackageBinding) + ? findType(name, (PackageBinding) resolvedImport, unitScope.fPackage) + : findDirectMemberType(name, (ReferenceBinding) resolvedImport); + if (temp != null && temp.isValidBinding()) { + if (someImport.reference != null) someImport.reference.used = true; + if (foundInImport) + // Answer error binding -- import on demand conflict; name found in two import on demand packages. + return new ProblemReferenceBinding(name, Ambiguous); + type = temp; + foundInImport = true; + } + } + } + } + if (type != null) + return type; + } + // see if the name is a package + if ((mask & PACKAGE) != 0) { + compilationUnitScope().recordSimpleReference(name); + PackageBinding packageBinding = unitScope.environment.getTopLevelPackage(name); + if (packageBinding != null) + return packageBinding; + } + + compilationUnitScope().recordSimpleReference(name); + // Answer error binding -- could not find name + if (foundType != null){ + return foundType; + } + return new ProblemReferenceBinding(name, NotFound); + } + + /* Answer whether the type is defined in the same compilation unit as the receiver + */ + public final boolean isDefinedInSameUnit(ReferenceBinding type) { + // find the outer most enclosing type + ReferenceBinding enclosingType = type; + while ((type = enclosingType.enclosingType()) != null) + enclosingType = type; + + // find the compilation unit scope + Scope scope, unitScope = this; + while ((scope = unitScope.parent) != null) + unitScope = scope; + + // test that the enclosingType is not part of the compilation unit + SourceTypeBinding[] topLevelTypes = + ((CompilationUnitScope) unitScope).topLevelTypes; + for (int i = topLevelTypes.length; --i >= 0;) + if (topLevelTypes[i] == enclosingType) + return true; + return false; + } + + public final boolean isJavaIoSerializable(TypeBinding tb) { + //a first -none optimized version-...:-).... + //please modify as needed + + return tb == getJavaIoSerializable(); + } + + public final boolean isJavaLangCloneable(TypeBinding tb) { + //a first -none optimized version-...:-).... + //please modify as needed + + return tb == getJavaLangCloneable(); + } + + public final boolean isJavaLangObject(TypeBinding type) { + return type.id == T_JavaLangObject; + } + + public final MethodScope methodScope() { + Scope scope = this; + do { + if (scope instanceof MethodScope) + return (MethodScope) scope; + scope = scope.parent; + } while (scope != null); + return null; + } + + // Internal use only + /* All methods in visible are acceptable matches for the method in question... + * The methods defined by the receiver type appear before those defined by its + * superclass and so on. We want to find the one which matches best. + * + * Since the receiver type is a class, we know each method's declaring class is + * either the receiver type or one of its superclasses. It is an error if the best match + * is defined by a superclass, when a lesser match is defined by the receiver type + * or a closer superclass. + */ + protected final MethodBinding mostSpecificClassMethodBinding(MethodBinding[] visible, int visibleSize) { + + MethodBinding method = null; + MethodBinding previous = null; + + nextVisible : for (int i = 0; i < visibleSize; i++) { + method = visible[i]; + + if (previous != null && method.declaringClass != previous.declaringClass) + break; // cannot answer a method farther up the hierarchy than the first method found + previous = method; + for (int j = 0; j < visibleSize; j++) { + if (i == j) continue; + MethodBinding next = visible[j]; + if (!areParametersAssignable(next.parameters, method.parameters)) + continue nextVisible; + } + compilationUnitScope().recordTypeReferences(method.thrownExceptions); + return method; + } + return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous); + } + + // Internal use only + /* All methods in visible are acceptable matches for the method in question... + * Since the receiver type is an interface, we ignore the possibility that 2 inherited + * but unrelated superinterfaces may define the same method in acceptable but + * not identical ways... we just take the best match that we find since any class which + * implements the receiver interface MUST implement all signatures for the method... + * in which case the best match is correct. + * + * NOTE: This is different than javac... in the following example, the message send of + * bar(X) in class Y is supposed to be ambiguous. But any class which implements the + * interface I MUST implement both signatures for bar. If this class was the receiver of + * the message send instead of the interface I, then no problem would be reported. + * + interface I1 { + void bar(J j); + } + interface I2 { + // void bar(J j); + void bar(Object o); + } + interface I extends I1, I2 {} + interface J {} + + class X implements J {} + + class Y extends X { + public void foo(I i, X x) { i.bar(x); } + } + */ + protected final MethodBinding mostSpecificInterfaceMethodBinding(MethodBinding[] visible, int visibleSize) { + MethodBinding method = null; + nextVisible : for (int i = 0; i < visibleSize; i++) { + method = visible[i]; + for (int j = 0; j < visibleSize; j++) { + if (i == j) continue; + MethodBinding next = visible[j]; + if (!areParametersAssignable(next.parameters, method.parameters)) + continue nextVisible; + } + compilationUnitScope().recordTypeReferences(method.thrownExceptions); + return method; + } + return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous); + } + + public final ClassScope outerMostClassScope() { + ClassScope lastClassScope = null; + Scope scope = this; + do { + if (scope instanceof ClassScope) + lastClassScope = (ClassScope) scope; + scope = scope.parent; + } while (scope != null); + return lastClassScope; // may answer null if no class around + } + + public final MethodScope outerMostMethodScope() { + MethodScope lastMethodScope = null; + Scope scope = this; + do { + if (scope instanceof MethodScope) + lastMethodScope = (MethodScope) scope; + scope = scope.parent; + } while (scope != null); + return lastMethodScope; // may answer null if no method around + } + + public final CompilationUnitDeclaration referenceCompilationUnit() { + Scope scope, unitScope = this; + while ((scope = unitScope.parent) != null) + unitScope = scope; + return ((CompilationUnitScope) unitScope).referenceContext; + } + // start position in this scope - for ordering scopes vs. variables + int startIndex() { + return 0; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/SourceTypeBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/SourceTypeBinding.java new file mode 100644 index 0000000..51d892a --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/SourceTypeBinding.java @@ -0,0 +1,1041 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import java.util.Enumeration; +import java.util.Hashtable; + +import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.Argument; +import net.sourceforge.phpdt.internal.compiler.ast.AssertStatement; +import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.MethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.TypeReference; +import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions; +import net.sourceforge.phpdt.internal.compiler.impl.Constant; +import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class SourceTypeBinding extends ReferenceBinding { + public ReferenceBinding superclass; + public ReferenceBinding[] superInterfaces; + public FieldBinding[] fields; + public MethodBinding[] methods; + public ReferenceBinding[] memberTypes; + + public ClassScope scope; + + // Synthetics are separated into 4 categories: methods, fields, class literals and changed declaring class bindings + public final static int METHOD = 0; + public final static int FIELD = 1; + public final static int CLASS_LITERAL = 2; + public final static int CHANGED_DECLARING_CLASS = 3; + + Hashtable[] synthetics; +protected SourceTypeBinding() { +} +public SourceTypeBinding(char[][] compoundName, PackageBinding fPackage, ClassScope scope) { + this.compoundName = compoundName; + this.fPackage = fPackage; + this.fileName = scope.referenceCompilationUnit().getFileName(); + this.modifiers = scope.referenceContext.modifiers; + this.sourceName = scope.referenceContext.name; + this.scope = scope; + + computeId(); +} +private void addDefaultAbstractMethod(MethodBinding abstractMethod) { + MethodBinding defaultAbstract = new MethodBinding( + abstractMethod.modifiers | AccDefaultAbstract, + abstractMethod.selector, + abstractMethod.returnType, + abstractMethod.parameters, + abstractMethod.thrownExceptions, + this); + + MethodBinding[] temp = new MethodBinding[methods.length + 1]; + System.arraycopy(methods, 0, temp, 0, methods.length); + temp[methods.length] = defaultAbstract; + methods = temp; +} +public void addDefaultAbstractMethods() { + if ((tagBits & KnowsDefaultAbstractMethods) != 0) return; + + tagBits |= KnowsDefaultAbstractMethods; + + if (isClass() && isAbstract()) { + if (fPackage.environment.options.targetJDK >= CompilerOptions.JDK1_2) return; // no longer added for post 1.2 targets + + ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][]; + int lastPosition = 0; + interfacesToVisit[lastPosition] = superInterfaces(); + + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) { + ReferenceBinding superType = interfaces[j]; + if (superType.isValidBinding()) { + MethodBinding[] methods = superType.methods(); + for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (!implementsMethod(method)) + addDefaultAbstractMethod(method); + } + + ReferenceBinding[] itsInterfaces = superType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } + } + } + } +} +/* Add a new synthetic field for . +* Answer the new field or the existing field if one already existed. +*/ + +public FieldBinding addSyntheticField(LocalVariableBinding actualOuterLocalVariable) { + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[FIELD] == null) { + synthetics[FIELD] = new Hashtable(5); + } + + FieldBinding synthField = (FieldBinding) synthetics[FIELD].get(actualOuterLocalVariable); + if (synthField == null) { + synthField = new SyntheticFieldBinding( + CharOperation.concat(SyntheticArgumentBinding.OuterLocalPrefix, actualOuterLocalVariable.name), + actualOuterLocalVariable.type, + AccPrivate | AccFinal | AccSynthetic, + this, + Constant.NotAConstant, + synthetics[FIELD].size()); + synthetics[FIELD].put(actualOuterLocalVariable, synthField); + } + + // ensure there is not already such a field defined by the user + boolean needRecheck; + int index = 1; + do { + needRecheck = false; + FieldBinding existingField; + if ((existingField = this.getField(synthField.name)) != null) { + TypeDeclaration typeDecl = scope.referenceContext; + for (int i = 0, max = typeDecl.fields.length; i < max; i++) { + FieldDeclaration fieldDecl = typeDecl.fields[i]; + if (fieldDecl.binding == existingField) { + synthField.name = CharOperation.concat( + SyntheticArgumentBinding.OuterLocalPrefix, + actualOuterLocalVariable.name, + ("$" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$ + needRecheck = true; + break; + } + } + } + } while (needRecheck); + return synthField; +} +/* Add a new synthetic field for . +* Answer the new field or the existing field if one already existed. +*/ + +public FieldBinding addSyntheticField(ReferenceBinding enclosingType) { + + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[FIELD] == null) { + synthetics[FIELD] = new Hashtable(5); + } + + FieldBinding synthField = (FieldBinding) synthetics[FIELD].get(enclosingType); + if (synthField == null) { + synthField = new SyntheticFieldBinding( + CharOperation.concat( + SyntheticArgumentBinding.EnclosingInstancePrefix, + String.valueOf(enclosingType.depth()).toCharArray()), + enclosingType, + AccPrivate | AccFinal | AccSynthetic, + this, + Constant.NotAConstant, + synthetics[FIELD].size()); + synthetics[FIELD].put(enclosingType, synthField); + } + // ensure there is not already such a field defined by the user + FieldBinding existingField; + if ((existingField = this.getField(synthField.name)) != null) { + TypeDeclaration typeDecl = scope.referenceContext; + for (int i = 0, max = typeDecl.fields.length; i < max; i++) { + FieldDeclaration fieldDecl = typeDecl.fields[i]; + if (fieldDecl.binding == existingField) { + scope.problemReporter().duplicateFieldInType(this, fieldDecl); + break; + } + } + } + return synthField; +} +/* Add a new synthetic field for a class literal access. +* Answer the new field or the existing field if one already existed. +*/ + +public FieldBinding addSyntheticField(TypeBinding targetType, BlockScope blockScope) { + + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[CLASS_LITERAL] == null) { + synthetics[CLASS_LITERAL] = new Hashtable(5); + } + + // use a different table than FIELDS, given there might be a collision between emulation of X.this$0 and X.class. + FieldBinding synthField = (FieldBinding) synthetics[CLASS_LITERAL].get(targetType); + if (synthField == null) { + synthField = new SyntheticFieldBinding( + ("class$" + synthetics[CLASS_LITERAL].size()).toCharArray(), //$NON-NLS-1$ + blockScope.getJavaLangClass(), + AccDefault | AccStatic | AccSynthetic, + this, + Constant.NotAConstant, + synthetics[CLASS_LITERAL].size()); + synthetics[CLASS_LITERAL].put(targetType, synthField); + } + // ensure there is not already such a field defined by the user + FieldBinding existingField; + if ((existingField = this.getField(synthField.name)) != null) { + TypeDeclaration typeDecl = blockScope.referenceType(); + for (int i = 0, max = typeDecl.fields.length; i < max; i++) { + FieldDeclaration fieldDecl = typeDecl.fields[i]; + if (fieldDecl.binding == existingField) { + blockScope.problemReporter().duplicateFieldInType(this, fieldDecl); + break; + } + } + } + return synthField; +} + +/* Add a new synthetic field for the emulation of the assert statement. +* Answer the new field or the existing field if one already existed. +*/ +public FieldBinding addSyntheticField(AssertStatement assertStatement, BlockScope blockScope) { + + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[FIELD] == null) { + synthetics[FIELD] = new Hashtable(5); + } + + FieldBinding synthField = (FieldBinding) synthetics[FIELD].get("assertionEmulation"); //$NON-NLS-1$ + if (synthField == null) { + synthField = new SyntheticFieldBinding( + "$assertionsDisabled".toCharArray(), //$NON-NLS-1$ + BooleanBinding, + AccDefault | AccStatic | AccSynthetic | AccFinal, + this, + Constant.NotAConstant, + 0); + synthetics[FIELD].put("assertionEmulation", synthField); //$NON-NLS-1$ + } + // ensure there is not already such a field defined by the user + // ensure there is not already such a field defined by the user + boolean needRecheck; + int index = 0; + do { + needRecheck = false; + FieldBinding existingField; + if ((existingField = this.getField(synthField.name)) != null) { + TypeDeclaration typeDecl = scope.referenceContext; + for (int i = 0, max = typeDecl.fields.length; i < max; i++) { + FieldDeclaration fieldDecl = typeDecl.fields[i]; + if (fieldDecl.binding == existingField) { + synthField.name = CharOperation.concat( + "$assertionsDisabled".toCharArray(), //$NON-NLS-1$ + ("_" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$ + needRecheck = true; + break; + } + } + } + } while (needRecheck); + return synthField; +} + +/* Add a new synthetic access method for read/write access to . + Answer the new method or the existing method if one already existed. +*/ + +public SyntheticAccessMethodBinding addSyntheticMethod(FieldBinding targetField, boolean isReadAccess) { + + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[METHOD] == null) { + synthetics[METHOD] = new Hashtable(5); + } + + SyntheticAccessMethodBinding accessMethod = null; + SyntheticAccessMethodBinding[] accessors = (SyntheticAccessMethodBinding[]) synthetics[METHOD].get(targetField); + if (accessors == null) { + accessMethod = new SyntheticAccessMethodBinding(targetField, isReadAccess, this); + synthetics[METHOD].put(targetField, accessors = new SyntheticAccessMethodBinding[2]); + accessors[isReadAccess ? 0 : 1] = accessMethod; + } else { + if ((accessMethod = accessors[isReadAccess ? 0 : 1]) == null) { + accessMethod = new SyntheticAccessMethodBinding(targetField, isReadAccess, this); + accessors[isReadAccess ? 0 : 1] = accessMethod; + } + } + return accessMethod; +} +/* Add a new synthetic access method for access to . + Answer the new method or the existing method if one already existed. +*/ + +public SyntheticAccessMethodBinding addSyntheticMethod(MethodBinding targetMethod) { + + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[METHOD] == null) { + synthetics[METHOD] = new Hashtable(5); + } + + SyntheticAccessMethodBinding accessMethod = (SyntheticAccessMethodBinding) synthetics[METHOD].get(targetMethod); + if (accessMethod == null) { + accessMethod = new SyntheticAccessMethodBinding(targetMethod, this); + synthetics[METHOD].put(targetMethod, accessMethod); + } + return accessMethod; +} + +public FieldBinding[] availableFields() { + return fields(); +} +public MethodBinding[] availableMethods() { + return methods(); +} +void faultInTypesForFieldsAndMethods() { + fields(); + methods(); + + for (int i = 0, length = memberTypes.length; i < length; i++) + ((SourceTypeBinding) memberTypes[i]).faultInTypesForFieldsAndMethods(); +} +// NOTE: the type of each field of a source type is resolved when needed + +public FieldBinding[] fields() { + + try { + int failed = 0; + for (int f = 0, max = fields.length; f < max; f++) { + if (resolveTypeFor(fields[f]) == null) { + fields[f] = null; + failed++; + } + } + if (failed > 0) { + int newSize = fields.length - failed; + if (newSize == 0) + return fields = NoFields; + + FieldBinding[] newFields = new FieldBinding[newSize]; + for (int i = 0, n = 0, max = fields.length; i < max; i++) + if (fields[i] != null) + newFields[n++] = fields[i]; + fields = newFields; + } + } catch(AbortCompilation e){ + // ensure null fields are removed + FieldBinding[] newFields = null; + int count = 0; + for (int i = 0, max = fields.length; i < max; i++){ + FieldBinding field = fields[i]; + if (field == null && newFields == null){ + System.arraycopy(fields, 0, newFields = new FieldBinding[max], 0, i); + } else if (newFields != null && field != null) { + newFields[count++] = field; + } + } + if (newFields != null){ + System.arraycopy(newFields, 0, fields = new FieldBinding[count], 0, count); + } + throw e; + } + return fields; +} +public MethodBinding[] getDefaultAbstractMethods() { + int count = 0; + for (int i = methods.length; --i >= 0;) + if (methods[i].isDefaultAbstract()) + count++; + if (count == 0) return NoMethods; + + MethodBinding[] result = new MethodBinding[count]; + count = 0; + for (int i = methods.length; --i >= 0;) + if (methods[i].isDefaultAbstract()) + result[count++] = methods[i]; + return result; +} +// NOTE: the return type, arg & exception types of each method of a source type are resolved when needed + +public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) { + int argCount = argumentTypes.length; + + if ((modifiers & AccUnresolved) == 0) { // have resolved all arg types & return type of the methods + nextMethod : for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (method.selector == ConstructorDeclaration.ConstantPoolName && method.parameters.length == argCount) { + TypeBinding[] toMatch = method.parameters; + for (int p = 0; p < argCount; p++) + if (toMatch[p] != argumentTypes[p]) + continue nextMethod; + return method; + } + } + } else { + MethodBinding[] methods = getMethods(ConstructorDeclaration.ConstantPoolName); // takes care of duplicates & default abstract methods + nextMethod : for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + TypeBinding[] toMatch = method.parameters; + if (toMatch.length == argCount) { + for (int p = 0; p < argCount; p++) + if (toMatch[p] != argumentTypes[p]) + continue nextMethod; + return method; + } + } + } + return null; +} +// NOTE: the return type, arg & exception types of each method of a source type are resolved when needed +// searches up the hierarchy as long as no potential (but not exact) match was found. + +public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes) { + int argCount = argumentTypes.length; + int selectorLength = selector.length; + boolean foundNothing = true; + + if ((modifiers & AccUnresolved) == 0) { // have resolved all arg types & return type of the methods + nextMethod : for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (method.selector.length == selectorLength && CharOperation.prefixEquals(method.selector, selector)) { + foundNothing = false; // inner type lookups must know that a method with this name exists + if (method.parameters.length == argCount) { + TypeBinding[] toMatch = method.parameters; + for (int p = 0; p < argCount; p++) + if (toMatch[p] != argumentTypes[p]) + continue nextMethod; + return method; + } + } + } + } else { + MethodBinding[] methods = getMethods(selector); // takes care of duplicates & default abstract methods + foundNothing = methods == NoMethods; + nextMethod : for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + TypeBinding[] toMatch = method.parameters; + if (toMatch.length == argCount) { + for (int p = 0; p < argCount; p++) + if (toMatch[p] != argumentTypes[p]) + continue nextMethod; + return method; + } + } + } + + if (foundNothing) { + if (isInterface()) { + if (superInterfaces.length == 1) + return superInterfaces[0].getExactMethod(selector, argumentTypes); + } else if (superclass != null) { + return superclass.getExactMethod(selector, argumentTypes); + } + } + return null; +} +// NOTE: the type of a field of a source type is resolved when needed + +public FieldBinding getField(char[] fieldName) { + int fieldLength = fieldName.length; + for (int f = fields.length; --f >= 0;) { + FieldBinding field = fields[f]; + if (field.name.length == fieldLength && CharOperation.prefixEquals(field.name, fieldName)) { + if (resolveTypeFor(field) != null) + return field; + + int newSize = fields.length - 1; + if (newSize == 0) { + fields = NoFields; + } else { + FieldBinding[] newFields = new FieldBinding[newSize]; + System.arraycopy(fields, 0, newFields, 0, f); + System.arraycopy(fields, f + 1, newFields, f, newSize - f); + fields = newFields; + } + return null; + } + } + return null; +} +// NOTE: the return type, arg & exception types of each method of a source type are resolved when needed + +public MethodBinding[] getMethods(char[] selector) { + // handle forward references to potential default abstract methods + addDefaultAbstractMethods(); + + try{ + int count = 0; + int lastIndex = -1; + int selectorLength = selector.length; + if ((modifiers & AccUnresolved) == 0) { // have resolved all arg types & return type of the methods + for (int m = 0, length = methods.length; m < length; m++) { + MethodBinding method = methods[m]; + if (method.selector.length == selectorLength && CharOperation.prefixEquals(method.selector, selector)) { + count++; + lastIndex = m; + } + } + } else { + boolean foundProblem = false; + int failed = 0; + for (int m = 0, length = methods.length; m < length; m++) { + MethodBinding method = methods[m]; + if (method.selector.length == selectorLength && CharOperation.prefixEquals(method.selector, selector)) { + if (resolveTypesFor(method) == null) { + foundProblem = true; + methods[m] = null; // unable to resolve parameters + failed++; + } else if (method.returnType == null) { + foundProblem = true; + } else { + count++; + lastIndex = m; + } + } + } + + if (foundProblem || count > 1) { + for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (method != null && method.selector.length == selectorLength && CharOperation.prefixEquals(method.selector, selector)) { + AbstractMethodDeclaration methodDecl = null; + for (int i = 0; i < m; i++) { + MethodBinding method2 = methods[i]; + if (method2 != null && CharOperation.equals(method.selector, method2.selector)) { + if (method.areParametersEqual(method2)) { + if (methodDecl == null) { + methodDecl = method.sourceMethod(); // cannot be retrieved after binding is lost + scope.problemReporter().duplicateMethodInType(this, methodDecl); + methodDecl.binding = null; + methods[m] = null; + failed++; + } + scope.problemReporter().duplicateMethodInType(this, method2.sourceMethod()); + method2.sourceMethod().binding = null; + methods[i] = null; + failed++; + } + } + } + if (method.returnType == null && methodDecl == null) { // forget method with invalid return type... was kept to detect possible collisions + method.sourceMethod().binding = null; + methods[m] = null; + failed++; + } + } + } + + if (failed > 0) { + int newSize = methods.length - failed; + if (newSize == 0) + return methods = NoMethods; + + MethodBinding[] newMethods = new MethodBinding[newSize]; + for (int i = 0, n = 0, max = methods.length; i < max; i++) + if (methods[i] != null) + newMethods[n++] = methods[i]; + methods = newMethods; + return getMethods(selector); // try again now that the problem methods have been removed + } + } + } + if (count == 1) + return new MethodBinding[] {methods[lastIndex]}; + if (count > 1) { + MethodBinding[] result = new MethodBinding[count]; + count = 0; + for (int m = 0; m <= lastIndex; m++) { + MethodBinding method = methods[m]; + if (method.selector.length == selectorLength && CharOperation.prefixEquals(method.selector, selector)) + result[count++] = method; + } + return result; + } + } catch(AbortCompilation e){ + // ensure null methods are removed + MethodBinding[] newMethods = null; + int count = 0; + for (int i = 0, max = methods.length; i < max; i++){ + MethodBinding method = methods[i]; + if (method == null && newMethods == null){ + System.arraycopy(methods, 0, newMethods = new MethodBinding[max], 0, i); + } else if (newMethods != null && method != null) { + newMethods[count++] = method; + } + } + if (newMethods != null){ + System.arraycopy(newMethods, 0, methods = new MethodBinding[count], 0, count); + } + modifiers ^= AccUnresolved; + throw e; + } + return NoMethods; +} +/* Answer the synthetic field for +* or null if one does not exist. +*/ + +public FieldBinding getSyntheticField(LocalVariableBinding actualOuterLocalVariable) { + + if (synthetics == null || synthetics[FIELD] == null) return null; + return (FieldBinding) synthetics[FIELD].get(actualOuterLocalVariable); +} +public ReferenceBinding[] memberTypes() { + return memberTypes; +} +public FieldBinding getUpdatedFieldBinding(FieldBinding targetField, ReferenceBinding newDeclaringClass) { + + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[CHANGED_DECLARING_CLASS] == null) { + synthetics[CHANGED_DECLARING_CLASS] = new Hashtable(5); + } + + Hashtable fieldMap = (Hashtable) synthetics[CHANGED_DECLARING_CLASS].get(targetField); + if (fieldMap == null) { + fieldMap = new Hashtable(5); + synthetics[CHANGED_DECLARING_CLASS].put(targetField, fieldMap); + } + FieldBinding updatedField = (FieldBinding) fieldMap.get(newDeclaringClass); + if (updatedField == null){ + updatedField = new FieldBinding(targetField, newDeclaringClass); + fieldMap.put(newDeclaringClass, updatedField); + } + return updatedField; +} + +public MethodBinding getUpdatedMethodBinding(MethodBinding targetMethod, ReferenceBinding newDeclaringClass) { + + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[CHANGED_DECLARING_CLASS] == null) { + synthetics[CHANGED_DECLARING_CLASS] = new Hashtable(5); + } + + + Hashtable methodMap = (Hashtable) synthetics[CHANGED_DECLARING_CLASS].get(targetMethod); + if (methodMap == null) { + methodMap = new Hashtable(5); + synthetics[CHANGED_DECLARING_CLASS].put(targetMethod, methodMap); + } + MethodBinding updatedMethod = (MethodBinding) methodMap.get(newDeclaringClass); + if (updatedMethod == null){ + updatedMethod = new MethodBinding(targetMethod, newDeclaringClass); + methodMap.put(newDeclaringClass, updatedMethod); + } + return updatedMethod; +} + +// NOTE: the return type, arg & exception types of each method of a source type are resolved when needed +public MethodBinding[] methods() { + try { + if ((modifiers & AccUnresolved) == 0) + return methods; + + int failed = 0; + for (int m = 0, max = methods.length; m < max; m++) { + if (resolveTypesFor(methods[m]) == null) { + methods[m] = null; // unable to resolve parameters + failed++; + } + } + + for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (method != null) { + AbstractMethodDeclaration methodDecl = null; + for (int i = 0; i < m; i++) { + MethodBinding method2 = methods[i]; + if (method2 != null && CharOperation.equals(method.selector, method2.selector)) { + if (method.areParametersEqual(method2)) { + if (methodDecl == null) { + methodDecl = method.sourceMethod(); // cannot be retrieved after binding is lost + scope.problemReporter().duplicateMethodInType(this, methodDecl); + methodDecl.binding = null; + methods[m] = null; + failed++; + } + scope.problemReporter().duplicateMethodInType(this, method2.sourceMethod()); + method2.sourceMethod().binding = null; + methods[i] = null; + failed++; + } + } + } + if (method.returnType == null && methodDecl == null) { // forget method with invalid return type... was kept to detect possible collisions + method.sourceMethod().binding = null; + methods[m] = null; + failed++; + } + } + } + + if (failed > 0) { + int newSize = methods.length - failed; + if (newSize == 0) { + methods = NoMethods; + } else { + MethodBinding[] newMethods = new MethodBinding[newSize]; + for (int m = 0, n = 0, max = methods.length; m < max; m++) + if (methods[m] != null) + newMethods[n++] = methods[m]; + methods = newMethods; + } + } + + // handle forward references to potential default abstract methods + addDefaultAbstractMethods(); + } catch(AbortCompilation e){ + // ensure null methods are removed + MethodBinding[] newMethods = null; + int count = 0; + for (int i = 0, max = methods.length; i < max; i++){ + MethodBinding method = methods[i]; + if (method == null && newMethods == null){ + System.arraycopy(methods, 0, newMethods = new MethodBinding[max], 0, i); + } else if (newMethods != null && method != null) { + newMethods[count++] = method; + } + } + if (newMethods != null){ + System.arraycopy(newMethods, 0, methods = new MethodBinding[count], 0, count); + } + modifiers ^= AccUnresolved; + throw e; + } + modifiers ^= AccUnresolved; + return methods; +} +private FieldBinding resolveTypeFor(FieldBinding field) { + if (field.type != null) + return field; + + FieldDeclaration[] fieldDecls = scope.referenceContext.fields; + for (int f = 0, length = fieldDecls.length; f < length; f++) { + if (fieldDecls[f].binding != field) + continue; + + field.type = fieldDecls[f].getTypeBinding(scope); + if (!field.type.isValidBinding()) { + scope.problemReporter().fieldTypeProblem(this, fieldDecls[f], field.type); + //scope.problemReporter().invalidType(fieldDecls[f].type, field.type); + fieldDecls[f].binding = null; + return null; + } + if (field.type == VoidBinding) { + scope.problemReporter().variableTypeCannotBeVoid(fieldDecls[f]); + fieldDecls[f].binding = null; + return null; + } + if (field.type.isArrayType() && ((ArrayBinding) field.type).leafComponentType == VoidBinding) { + scope.problemReporter().variableTypeCannotBeVoidArray(fieldDecls[f]); + fieldDecls[f].binding = null; + return null; + } + return field; + } + return null; // should never reach this point +} +private MethodBinding resolveTypesFor(MethodBinding method) { + if ((method.modifiers & AccUnresolved) == 0) + return method; + + AbstractMethodDeclaration methodDecl = method.sourceMethod(); + TypeReference[] exceptionTypes = methodDecl.thrownExceptions; + if (exceptionTypes != null) { + int size = exceptionTypes.length; + method.thrownExceptions = new ReferenceBinding[size]; + ReferenceBinding throwable = scope.getJavaLangThrowable(); + int count = 0; + ReferenceBinding resolvedExceptionType; + for (int i = 0; i < size; i++) { + resolvedExceptionType = (ReferenceBinding) exceptionTypes[i].getTypeBinding(scope); + if (!resolvedExceptionType.isValidBinding()) { + methodDecl.scope.problemReporter().exceptionTypeProblem(this, methodDecl, exceptionTypes[i], resolvedExceptionType); + //methodDecl.scope.problemReporter().invalidType(exceptionTypes[i], resolvedExceptionType); + continue; + } + if (throwable != resolvedExceptionType && !throwable.isSuperclassOf(resolvedExceptionType)) { + methodDecl.scope.problemReporter().cannotThrowType(this, methodDecl, exceptionTypes[i], resolvedExceptionType); + continue; + } + method.thrownExceptions[count++] = resolvedExceptionType; + } + if (count < size) + System.arraycopy(method.thrownExceptions, 0, method.thrownExceptions = new ReferenceBinding[count], 0, count); + } + + boolean foundArgProblem = false; + Argument[] arguments = methodDecl.arguments; + if (arguments != null) { + int size = arguments.length; + method.parameters = new TypeBinding[size]; + for (int i = 0; i < size; i++) { + Argument arg = arguments[i]; + method.parameters[i] = arg.type.getTypeBinding(scope); + if (!method.parameters[i].isValidBinding()) { + methodDecl.scope.problemReporter().argumentTypeProblem(this, methodDecl, arg, method.parameters[i]); + //methodDecl.scope.problemReporter().invalidType(arg, method.parameters[i]); + foundArgProblem = true; + } else if (method.parameters[i] == VoidBinding) { + methodDecl.scope.problemReporter().argumentTypeCannotBeVoid(this, methodDecl, arg); + foundArgProblem = true; + } else if (method.parameters[i].isArrayType() && ((ArrayBinding) method.parameters[i]).leafComponentType == VoidBinding) { + methodDecl.scope.problemReporter().argumentTypeCannotBeVoidArray(this, methodDecl, arg); + foundArgProblem = true; + } + } + } + + boolean foundReturnTypeProblem = false; + if (!method.isConstructor()) { + TypeReference returnType = ((MethodDeclaration) methodDecl).returnType; + if (returnType == null) { + methodDecl.scope.problemReporter().missingReturnType(methodDecl); + method.returnType = null; + foundReturnTypeProblem = true; + } else { + method.returnType = returnType.getTypeBinding(scope); + if (!method.returnType.isValidBinding()) { + methodDecl.scope.problemReporter().returnTypeProblem(this, (MethodDeclaration) methodDecl, method.returnType); + //methodDecl.scope.problemReporter().invalidType(returnType, method.returnType); + method.returnType = null; + foundReturnTypeProblem = true; + } else if (method.returnType.isArrayType() && ((ArrayBinding) method.returnType).leafComponentType == VoidBinding) { + methodDecl.scope.problemReporter().returnTypeCannotBeVoidArray(this, (MethodDeclaration) methodDecl); + method.returnType = null; + foundReturnTypeProblem = true; + } + } + } + if (foundArgProblem) { + methodDecl.binding = null; + return null; + } + if (foundReturnTypeProblem) + return method; // but its still unresolved with a null return type & is still connected to its method declaration + + method.modifiers ^= AccUnresolved; + return method; +} +public final int sourceEnd() { + return scope.referenceContext.sourceEnd; +} +public final int sourceStart() { + return scope.referenceContext.sourceStart; +} +public ReferenceBinding superclass() { + return superclass; +} +public ReferenceBinding[] superInterfaces() { + return superInterfaces; +} +public SyntheticAccessMethodBinding[] syntheticAccessMethods() { + + if (synthetics == null || synthetics[METHOD] == null || synthetics[METHOD].size() == 0) return null; + + // difficult to compute size up front because of the embedded arrays so assume there is only 1 + int index = 0; + SyntheticAccessMethodBinding[] bindings = new SyntheticAccessMethodBinding[1]; + Enumeration fieldsOrMethods = synthetics[METHOD].keys(); + while (fieldsOrMethods.hasMoreElements()) { + Object fieldOrMethod = fieldsOrMethods.nextElement(); + if (fieldOrMethod instanceof MethodBinding) { + if (index + 1 > bindings.length) + System.arraycopy(bindings, 0, (bindings = new SyntheticAccessMethodBinding[index + 1]), 0, index); + bindings[index++] = (SyntheticAccessMethodBinding) synthetics[METHOD].get(fieldOrMethod); + } else { + SyntheticAccessMethodBinding[] fieldAccessors = (SyntheticAccessMethodBinding[]) synthetics[METHOD].get(fieldOrMethod); + int numberOfAccessors = 0; + if (fieldAccessors[0] != null) numberOfAccessors++; + if (fieldAccessors[1] != null) numberOfAccessors++; + if (index + numberOfAccessors > bindings.length) + System.arraycopy(bindings, 0, (bindings = new SyntheticAccessMethodBinding[index + numberOfAccessors]), 0, index); + if (fieldAccessors[0] != null) + bindings[index++] = fieldAccessors[0]; + if (fieldAccessors[1] != null) + bindings[index++] = fieldAccessors[1]; + } + } + + // sort them in according to their own indexes + int length; + SyntheticAccessMethodBinding[] sortedBindings = new SyntheticAccessMethodBinding[length = bindings.length]; + for (int i = 0; i < length; i++){ + SyntheticAccessMethodBinding binding = bindings[i]; + sortedBindings[binding.index] = binding; + } + return sortedBindings; +} +/** + * Answer the collection of synthetic fields to append into the classfile + */ +public FieldBinding[] syntheticFields() { + + if (synthetics == null) return null; + + int fieldSize = synthetics[FIELD] == null ? 0 : synthetics[FIELD].size(); + int literalSize = synthetics[CLASS_LITERAL] == null ? 0 :synthetics[CLASS_LITERAL].size(); + int totalSize = fieldSize + literalSize; + if (totalSize == 0) return null; + FieldBinding[] bindings = new FieldBinding[totalSize]; + + // add innerclass synthetics + if (synthetics[FIELD] != null){ + Enumeration elements = synthetics[FIELD].elements(); + for (int i = 0; i < fieldSize; i++) { + SyntheticFieldBinding synthBinding = (SyntheticFieldBinding) elements.nextElement(); + bindings[synthBinding.index] = synthBinding; + } + } + // add class literal synthetics + if (synthetics[CLASS_LITERAL] != null){ + Enumeration elements = synthetics[CLASS_LITERAL].elements(); + for (int i = 0; i < literalSize; i++) { + SyntheticFieldBinding synthBinding = (SyntheticFieldBinding) elements.nextElement(); + bindings[fieldSize+synthBinding.index] = synthBinding; + } + } + return bindings; +} +public String toString() { + String s = "(id="+(id == NoId ? "NoId" : (""+id) ) +")\n"; //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-4$ //$NON-NLS-1$ + + if (isDeprecated()) s += "deprecated "; //$NON-NLS-1$ + if (isPublic()) s += "public "; //$NON-NLS-1$ + if (isProtected()) s += "protected "; //$NON-NLS-1$ + if (isPrivate()) s += "private "; //$NON-NLS-1$ + if (isAbstract() && isClass()) s += "abstract "; //$NON-NLS-1$ + if (isStatic() && isNestedType()) s += "static "; //$NON-NLS-1$ + if (isFinal()) s += "final "; //$NON-NLS-1$ + + s += isInterface() ? "interface " : "class "; //$NON-NLS-1$ //$NON-NLS-2$ + s += (compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED TYPE"; //$NON-NLS-1$ + + s += "\n\textends "; //$NON-NLS-1$ + s += (superclass != null) ? superclass.debugName() : "NULL TYPE"; //$NON-NLS-1$ + + if (superInterfaces != null) { + if (superInterfaces != NoSuperInterfaces) { + s += "\n\timplements : "; //$NON-NLS-1$ + for (int i = 0, length = superInterfaces.length; i < length; i++) { + if (i > 0) + s += ", "; //$NON-NLS-1$ + s += (superInterfaces[i] != null) ? superInterfaces[i].debugName() : "NULL TYPE"; //$NON-NLS-1$ + } + } + } else { + s += "NULL SUPERINTERFACES"; //$NON-NLS-1$ + } + + if (enclosingType() != null) { + s += "\n\tenclosing type : "; //$NON-NLS-1$ + s += enclosingType().debugName(); + } + + if (fields != null) { + if (fields != NoFields) { + s += "\n/* fields */"; //$NON-NLS-1$ + for (int i = 0, length = fields.length; i < length; i++) + s += (fields[i] != null) ? "\n" + fields[i].toString() : "\nNULL FIELD"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } else { + s += "NULL FIELDS"; //$NON-NLS-1$ + } + + if (methods != null) { + if (methods != NoMethods) { + s += "\n/* methods */"; //$NON-NLS-1$ + for (int i = 0, length = methods.length; i < length; i++) + s += (methods[i] != null) ? "\n" + methods[i].toString() : "\nNULL METHOD"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } else { + s += "NULL METHODS"; //$NON-NLS-1$ + } + + if (memberTypes != null) { + if (memberTypes != NoMemberTypes) { + s += "\n/* members */"; //$NON-NLS-1$ + for (int i = 0, length = memberTypes.length; i < length; i++) + s += (memberTypes[i] != null) ? "\n" + memberTypes[i].toString() : "\nNULL TYPE"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } else { + s += "NULL MEMBER TYPES"; //$NON-NLS-1$ + } + + s += "\n\n\n"; //$NON-NLS-1$ + return s; +} +void verifyMethods(MethodVerifier verifier) { + verifier.verify(this); + + for (int i = memberTypes.length; --i >= 0;) + ((SourceTypeBinding) memberTypes[i]).verifyMethods(verifier); +} + +/* Answer the synthetic field for +* or null if one does not exist. +*/ + +public FieldBinding getSyntheticField(ReferenceBinding targetEnclosingType, BlockScope scope, boolean onlyExactMatch) { + + if (synthetics == null || synthetics[FIELD] == null) return null; + FieldBinding field = (FieldBinding) synthetics[FIELD].get(targetEnclosingType); + if (field != null) return field; + + // type compatibility : to handle cases such as + // class T { class M{}} + // class S extends T { class N extends M {}} --> need to use S as a default enclosing instance for the super constructor call in N(). + if (!onlyExactMatch){ + Enumeration enum = synthetics[FIELD].elements(); + while (enum.hasMoreElements()) { + field = (FieldBinding) enum.nextElement(); + if (CharOperation.startsWith(field.name, SyntheticArgumentBinding.EnclosingInstancePrefix) + && targetEnclosingType.isSuperclassOf((ReferenceBinding) field.type)) + return field; + } + } + return null; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/SyntheticAccessMethodBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/SyntheticAccessMethodBinding.java new file mode 100644 index 0000000..f7c0e41 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/SyntheticAccessMethodBinding.java @@ -0,0 +1,283 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class SyntheticAccessMethodBinding extends MethodBinding { + + public FieldBinding targetReadField; // read access to a field + public FieldBinding targetWriteField; // write access to a field + public MethodBinding targetMethod; // method or constructor + + public int accessType; + + public final static int FieldReadAccess = 1; + public final static int FieldWriteAccess = 2; + public final static int MethodAccess = 3; + public final static int ConstructorAccess = 4; + + final static char[] AccessMethodPrefix = { 'a', 'c', 'c', 'e', 's', 's', '$' }; + + public int sourceStart = 0; // start position of the matching declaration + public int index; // used for sorting access methods in the class file +public SyntheticAccessMethodBinding(FieldBinding targetField, boolean isReadAccess, ReferenceBinding declaringClass) { + this.modifiers = AccDefault | AccStatic | AccSynthetic; + SourceTypeBinding declaringSourceType = (SourceTypeBinding) declaringClass; + SyntheticAccessMethodBinding[] knownAccessMethods = declaringSourceType.syntheticAccessMethods(); + int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length; + this.index = methodId; + this.selector = CharOperation.concat(AccessMethodPrefix, String.valueOf(methodId).toCharArray()); + if (isReadAccess) { + this.returnType = targetField.type; + if (targetField.isStatic()) { + this.parameters = NoParameters; + } else { + this.parameters = new TypeBinding[1]; + this.parameters[0] = declaringSourceType; + } + this.targetReadField = targetField; + this.accessType = FieldReadAccess; + } else { + this.returnType = VoidBinding; + if (targetField.isStatic()) { + this.parameters = new TypeBinding[1]; + this.parameters[0] = targetField.type; + } else { + this.parameters = new TypeBinding[2]; + this.parameters[0] = declaringSourceType; + this.parameters[1] = targetField.type; + } + this.targetWriteField = targetField; + this.accessType = FieldWriteAccess; + } + this.thrownExceptions = NoExceptions; + this.declaringClass = declaringSourceType; + + // check for method collision + boolean needRename; + do { + check : { + needRename = false; + // check for collision with known methods + MethodBinding[] methods = declaringSourceType.methods; + for (int i = 0, length = methods.length; i < length; i++) { + if (this.selector == methods[i].selector && this.areParametersEqual(methods[i])) { + needRename = true; + break check; + } + } + // check for collision with synthetic accessors + if (knownAccessMethods != null) { + for (int i = 0, length = knownAccessMethods.length; i < length; i++) { + if (knownAccessMethods[i] == null) continue; + if (this.selector == knownAccessMethods[i].selector && this.areParametersEqual(methods[i])) { + needRename = true; + break check; + } + } + } + } + if (needRename) { // retry with a selector postfixed by a growing methodId + this.selector(CharOperation.concat(AccessMethodPrefix, String.valueOf(++methodId).toCharArray())); + } + } while (needRename); + + // retrieve sourceStart position for the target field for line number attributes + FieldDeclaration[] fieldDecls = declaringSourceType.scope.referenceContext.fields; + if (fieldDecls != null) { + for (int i = 0, max = fieldDecls.length; i < max; i++) { + if (fieldDecls[i].binding == targetField) { + this.sourceStart = fieldDecls[i].sourceStart; + return; + } + } + } + +/* did not find the target field declaration - it is a synthetic one + public class A { + public class B { + public class C { + void foo() { + System.out.println("A.this = " + A.this); + } + } + } + public static void main(String args[]) { + new A().new B().new C().foo(); + } + } +*/ + // We now at this point - per construction - it is for sure an enclosing instance, we are going to + // show the target field type declaration location. + this.sourceStart = declaringSourceType.scope.referenceContext.sourceStart; // use the target declaring class name position instead +} +public SyntheticAccessMethodBinding(MethodBinding targetMethod, ReferenceBinding receiverType) { + + if (targetMethod.isConstructor()) { + this.initializeConstructorAccessor(targetMethod); + } else { + this.initializeMethodAccessor(targetMethod, receiverType); + } +} +/** + * An constructor accessor is a constructor with an extra argument (declaringClass), in case of + * collision with an existing constructor, then add again an extra argument (declaringClass again). + */ + public void initializeConstructorAccessor(MethodBinding targetConstructor) { + + this.targetMethod = targetConstructor; + this.modifiers = AccDefault | AccSynthetic; + SourceTypeBinding sourceType = + (SourceTypeBinding) targetConstructor.declaringClass; + SyntheticAccessMethodBinding[] knownAccessMethods = + sourceType.syntheticAccessMethods(); + this.index = knownAccessMethods == null ? 0 : knownAccessMethods.length; + + this.selector = targetConstructor.selector; + this.returnType = targetConstructor.returnType; + this.accessType = ConstructorAccess; + this.parameters = new TypeBinding[targetConstructor.parameters.length + 1]; + System.arraycopy( + targetConstructor.parameters, + 0, + this.parameters, + 0, + targetConstructor.parameters.length); + parameters[targetConstructor.parameters.length] = + targetConstructor.declaringClass; + this.thrownExceptions = targetConstructor.thrownExceptions; + this.declaringClass = sourceType; + + // check for method collision + boolean needRename; + do { + check : { + needRename = false; + // check for collision with known methods + MethodBinding[] methods = sourceType.methods; + for (int i = 0, length = methods.length; i < length; i++) { + if (this.selector == methods[i].selector + && this.areParametersEqual(methods[i])) { + needRename = true; + break check; + } + } + // check for collision with synthetic accessors + if (knownAccessMethods != null) { + for (int i = 0, length = knownAccessMethods.length; i < length; i++) { + if (knownAccessMethods[i] == null) + continue; + if (this.selector == knownAccessMethods[i].selector + && this.areParametersEqual(methods[i])) { + needRename = true; + break check; + } + } + } + } + if (needRename) { // retry with a new extra argument + int length = this.parameters.length; + System.arraycopy( + this.parameters, + 0, + this.parameters = new TypeBinding[length + 1], + 0, + length); + this.parameters[length] = this.declaringClass; + } + } while (needRename); + + // retrieve sourceStart position for the target method for line number attributes + AbstractMethodDeclaration[] methodDecls = + sourceType.scope.referenceContext.methods; + if (methodDecls != null) { + for (int i = 0, length = methodDecls.length; i < length; i++) { + if (methodDecls[i].binding == targetConstructor) { + this.sourceStart = methodDecls[i].sourceStart; + return; + } + } + } +} +/** + * An method accessor is a method with an access$N selector, where N is incremented in case of collisions. + */ + +public void initializeMethodAccessor(MethodBinding targetMethod, ReferenceBinding declaringClass) { + + this.targetMethod = targetMethod; + this.modifiers = AccDefault | AccStatic | AccSynthetic; + SourceTypeBinding declaringSourceType = (SourceTypeBinding) declaringClass; + SyntheticAccessMethodBinding[] knownAccessMethods = declaringSourceType.syntheticAccessMethods(); + int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length; + this.index = methodId; + + this.selector = CharOperation.concat(AccessMethodPrefix, String.valueOf(methodId).toCharArray()); + this.returnType = targetMethod.returnType; + this.accessType = MethodAccess; + + if (targetMethod.isStatic()) { + this.parameters = targetMethod.parameters; + } else { + this.parameters = new TypeBinding[targetMethod.parameters.length + 1]; + this.parameters[0] = declaringSourceType; + System.arraycopy(targetMethod.parameters, 0, this.parameters, 1, targetMethod.parameters.length); + } + this.thrownExceptions = targetMethod.thrownExceptions; + this.declaringClass = declaringSourceType; + + // check for method collision + boolean needRename; + do { + check : { + needRename = false; + // check for collision with known methods + MethodBinding[] methods = declaringSourceType.methods; + for (int i = 0, length = methods.length; i < length; i++) { + if (this.selector == methods[i].selector && this.areParametersEqual(methods[i])) { + needRename = true; + break check; + } + } + // check for collision with synthetic accessors + if (knownAccessMethods != null) { + for (int i = 0, length = knownAccessMethods.length; i < length; i++) { + if (knownAccessMethods[i] == null) continue; + if (this.selector == knownAccessMethods[i].selector && this.areParametersEqual(methods[i])) { + needRename = true; + break check; + } + } + } + } + if (needRename) { // retry with a selector & a growing methodId + this.selector(CharOperation.concat(AccessMethodPrefix, String.valueOf(++methodId).toCharArray())); + } + } while (needRename); + + // retrieve sourceStart position for the target method for line number attributes + AbstractMethodDeclaration[] methodDecls = declaringSourceType.scope.referenceContext.methods; + if (methodDecls != null) { + for (int i = 0, length = methodDecls.length; i < length; i++) { + if (methodDecls[i].binding == targetMethod) { + this.sourceStart = methodDecls[i].sourceStart; + return; + } + } + } +} +protected boolean isConstructorRelated() { + return accessType == ConstructorAccess; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/SyntheticArgumentBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/SyntheticArgumentBinding.java new file mode 100644 index 0000000..5ef5fbf --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/SyntheticArgumentBinding.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +/** + * Specific local variable location used to: + * - either provide emulation for outer local variables used from within innerclass constructs, + * - or provide emulation to enclosing instances. + * When it is mapping to an outer local variable, this actual outer local is accessible through + * the public field #actualOuterLocalVariable. + * + * Such a synthetic argument binding will be inserted in all constructors of local innertypes before + * the user arguments. + */ + +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class SyntheticArgumentBinding extends LocalVariableBinding { + + { + this.isArgument = true; + this.used = true; + } + // if the argument is mapping to an outer local variable, this denotes the outer actual variable + public LocalVariableBinding actualOuterLocalVariable; + // if the argument has a matching synthetic field + public FieldBinding matchingField; + + final static char[] OuterLocalPrefix = { 'v', 'a', 'l', '$' }; + final static char[] EnclosingInstancePrefix = { 't', 'h', 'i', 's', '$' }; +public SyntheticArgumentBinding(LocalVariableBinding actualOuterLocalVariable) { + super( + CharOperation.concat(OuterLocalPrefix, actualOuterLocalVariable.name), + actualOuterLocalVariable.type, + AccFinal, + true); + this.actualOuterLocalVariable = actualOuterLocalVariable; +} +public SyntheticArgumentBinding(ReferenceBinding enclosingType) { + super( + CharOperation.concat( + SyntheticArgumentBinding.EnclosingInstancePrefix, + String.valueOf(enclosingType.depth()).toCharArray()), + enclosingType, + AccFinal, + true); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/SyntheticFieldBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/SyntheticFieldBinding.java new file mode 100644 index 0000000..47006bf --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/SyntheticFieldBinding.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.impl.Constant; + +public class SyntheticFieldBinding extends FieldBinding { + public int index; +public SyntheticFieldBinding(char[] name, TypeBinding type, int modifiers, ReferenceBinding declaringClass, Constant constant, int index) { + super(name, type, modifiers, declaringClass, constant); + this.index = index; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/TagBits.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/TagBits.java new file mode 100644 index 0000000..5f5c827 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/TagBits.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +public interface TagBits { + // Tag bits in the tagBits int of every TypeBinding + final int IsArrayType = 0x0001; + final int IsBaseType = 0x0002; + final int IsNestedType = 0x0004; + final int IsMemberType = 0x0008; + final int MemberTypeMask = IsNestedType | IsMemberType; + final int IsLocalType = 0x0010; + final int LocalTypeMask = IsNestedType | IsLocalType; + final int IsAnonymousType = 0x0020; + final int AnonymousTypeMask = LocalTypeMask | IsAnonymousType; + final int IsBinaryBinding = 0x0040; + + // for the type hierarchy check used by ClassScope + final int BeginHierarchyCheck = 0x0100; + final int EndHierarchyCheck = 0x0200; + + // test bit to see if default abstract methods were computed + final int KnowsDefaultAbstractMethods = 0x0400; + + // Reusable bit currently used by Scopes + final int InterfaceVisited = 0x0800; + + // test bits to see if parts of binary types are faulted + final int AreFieldsComplete = 0x1000; + final int AreMethodsComplete = 0x2000; + + // test bit to avoid asking a type for a member type (includes inherited member types) + final int HasNoMemberTypes = 0x4000; + + // test bit to identify if the type's hierarchy is inconsistent + final int HierarchyHasProblems = 0x8000; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/TypeBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/TypeBinding.java new file mode 100644 index 0000000..aea6a64 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/TypeBinding.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +/* + * Not all fields defined by this type (& its subclasses) are initialized when it is created. + * Some are initialized only when needed. + * + * Accessors have been provided for some public fields so all TypeBindings have the same API... + * but access public fields directly whenever possible. + * Non-public fields have accessors which should be used everywhere you expect the field to be initialized. + * + * null is NOT a valid value for a non-public field... it just means the field is not initialized. + */ +abstract public class TypeBinding extends Binding implements BaseTypes, TagBits, TypeConstants, TypeIds { + public int id = NoId; + public int tagBits = 0; // See values in the interface TagBits below +/* API + * Answer the receiver's binding type from Binding.BindingID. + */ + +public final int bindingType() { + return TYPE; +} +/* Answer true if the receiver can be instantiated + */ + +public boolean canBeInstantiated() { + return !isBaseType(); +} +/* Answer the receiver's constant pool name. + * + * NOTE: This method should only be used during/after code gen. + */ + +public abstract char[] constantPoolName(); /* java/lang/Object */ +String debugName() { + return new String(readableName()); +} +public abstract PackageBinding getPackage(); +/* Answer true if the receiver is an array +*/ + +public final boolean isArrayType() { + return (tagBits & IsArrayType) != 0; +} +/* Answer true if the receiver is a base type +*/ + +public final boolean isBaseType() { + return (tagBits & IsBaseType) != 0; +} +public boolean isClass() { + return false; +} +/* Answer true if the receiver type can be assigned to the argument type (right) +*/ + +abstract boolean isCompatibleWith(TypeBinding right); +/* Answer true if the receiver's hierarchy has problems (always false for arrays & base types) +*/ + +public final boolean isHierarchyInconsistent() { + return (tagBits & HierarchyHasProblems) != 0; +} +public boolean isInterface() { + return false; +} +public final boolean isNumericType() { + switch (id) { + case T_int : + case T_float : + case T_double : + case T_short : + case T_byte : + case T_long : + case T_char : + return true; + default : + return false; + } +} + +public TypeBinding leafComponentType(){ + return this; +} + +/** + * Answer the qualified name of the receiver's package separated by periods + * or an empty string if its the default package. + * + * For example, {java.util.Hashtable}. + */ + +public char[] qualifiedPackageName() { + return getPackage() == null ? NoChar : getPackage().readableName(); +} +/** +* Answer the source name for the type. +* In the case of member types, as the qualified name from its top level type. +* For example, for a member type N defined inside M & A: "A.M.N". +*/ + +public abstract char[] qualifiedSourceName(); +/* Answer the receiver's signature. +* +* Arrays & base types do not distinguish between signature() & constantPoolName(). +* +* NOTE: This method should only be used during/after code gen. +*/ + +public char[] signature() { + return constantPoolName(); +} +public abstract char[] sourceName(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/TypeConstants.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/TypeConstants.java new file mode 100644 index 0000000..2fbccdf --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/TypeConstants.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +public interface TypeConstants { + final char[] JAVA = new char[] {'j', 'a', 'v', 'a'}; + final char[] LANG = new char[] {'l', 'a', 'n', 'g'}; + final char[] IO = new char[] {'i', 'o'}; + final char[] REFLECT = new char[] {'r', 'e', 'f', 'l', 'e', 'c', 't'}; + final char[] CharArray_JAVA_LANG_OBJECT = new char[] {'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}; + final char[] LENGTH = new char[] {'l', 'e', 'n', 'g', 't', 'h'}; + final char[] CLONE = new char[] {'c', 'l', 'o', 'n', 'e'}; + + // Constant compound names + final char[][] JAVA_LANG = new char[][] {JAVA, LANG}; + final char[][] JAVA_IO = new char[][] {JAVA, IO}; + final char[][] JAVA_LANG_ASSERTIONERROR = new char[][] {JAVA, LANG, "AssertionError".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_CLASS = new char[][] {JAVA, LANG, {'C', 'l', 'a', 's', 's'}}; + final char[][] JAVA_LANG_CLASSNOTFOUNDEXCEPTION = new char[][] {JAVA, LANG, {'C', 'l', 'a', 's', 's', 'N', 'o', 't', 'F', 'o', 'u', 'n', 'd', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n'}}; + final char[][] JAVA_LANG_CLONEABLE = new char[][] {JAVA, LANG, {'C', 'l', 'o', 'n', 'e', 'a', 'b', 'l', 'e'}}; + final char[][] JAVA_LANG_EXCEPTION = new char[][] {JAVA, LANG, {'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n'}}; + final char[][] JAVA_LANG_ERROR = new char[][] {JAVA, LANG, {'E', 'r', 'r', 'o', 'r'}}; + final char[][] JAVA_LANG_NOCLASSDEFERROR = new char[][] {JAVA, LANG, {'N', 'o', 'C', 'l', 'a', 's', 's', 'D', 'e', 'f', 'E', 'r', 'r', 'o', 'r'}}; + final char[][] JAVA_LANG_OBJECT = new char[][] {JAVA, LANG, {'O', 'b', 'j', 'e', 'c', 't'}}; + final char[][] JAVA_LANG_STRING = new char[][] {JAVA, LANG, {'S', 't', 'r', 'i', 'n', 'g'}}; + final char[][] JAVA_LANG_STRINGBUFFER = new char[][] {JAVA, LANG, {'S', 't', 'r', 'i', 'n', 'g', 'B', 'u', 'f', 'f', 'e', 'r'}}; + final char[][] JAVA_LANG_SYSTEM = new char[][] {JAVA, LANG, {'S', 'y', 's', 't', 'e', 'm'}}; + final char[][] JAVA_LANG_RUNTIMEEXCEPTION = new char[][] {JAVA, LANG, {'R', 'u', 'n', 't', 'i', 'm', 'e', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n'}}; + final char[][] JAVA_LANG_THROWABLE = new char[][] {JAVA, LANG, {'T', 'h', 'r', 'o', 'w', 'a', 'b', 'l', 'e'}}; + final char[][] JAVA_LANG_REFLECT_CONSTRUCTOR = new char[][] {JAVA, LANG, REFLECT, {'C', 'o', 'n', 's', 't', 'r', 'u', 'c', 't', 'o', 'r'}}; + final char[][] JAVA_IO_PRINTSTREAM = new char[][] {JAVA, IO, {'P', 'r', 'i', 'n', 't', 'S', 't', 'r', 'e', 'a', 'm'}}; + final char[][] JAVA_IO_SERIALIZABLE = new char[][] {JAVA, IO, {'S', 'e', 'r', 'i', 'a', 'l', 'i', 'z', 'a', 'b', 'l', 'e'}}; + final char[][] JAVA_LANG_BYTE = new char[][] {JAVA, LANG, "Byte".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_SHORT = new char[][] {JAVA, LANG, "Short".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_CHARACTER = new char[][] {JAVA, LANG, "Character".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_INTEGER = new char[][] {JAVA, LANG, "Integer".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_LONG = new char[][] {JAVA, LANG, "Long".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_FLOAT = new char[][] {JAVA, LANG, "Float".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_DOUBLE = new char[][] {JAVA, LANG, "Double".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_BOOLEAN = new char[][] {JAVA, LANG, "Boolean".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_VOID = new char[][] {JAVA, LANG, "Void".toCharArray()}; //$NON-NLS-1$ + + // Constants used by the flow analysis + final int EqualOrMoreSpecific = -1; + final int NotRelated = 0; + final int MoreGeneric = 1; + + // Empty Collection which can later assign to null if performance is an issue. + final char[] NoChar = new char[0]; + final char[][] NoCharChar = new char[0][]; + // Method collections + final TypeBinding[] NoParameters = new TypeBinding[0]; + final ReferenceBinding[] NoExceptions = new ReferenceBinding[0]; + // Type collections + final FieldBinding[] NoFields = new FieldBinding[0]; + final MethodBinding[] NoMethods = new MethodBinding[0]; + final ReferenceBinding[] NoSuperInterfaces = new ReferenceBinding[0]; + final ReferenceBinding[] NoMemberTypes = new ReferenceBinding[0]; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/TypeIds.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/TypeIds.java new file mode 100644 index 0000000..8c41524 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/TypeIds.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +public interface TypeIds { + //base type void null undefined Object String + //should have an id that is 0<= id <= 15 + + final int T_undefined = 0; // should not be changed + final int T_Object = 1; + final int T_char = 2; + final int T_byte = 3; + final int T_short = 4; + final int T_boolean = 5; + final int T_void = 6; + final int T_long = 7; + final int T_double = 8; + final int T_float = 9; + final int T_int = 10; + final int T_String = 11; + final int T_null = 12; + //final int T_extendedDouble = 13; + //final int T_extendedLong = 14 + + //=========end of 4 bits constraint=========== + + final int T_JavaLangObject = T_Object; // for consistency + final int T_JavaLangString = T_String; // for consistency + + // well-known exception types + final int T_JavaLangClass = 16; + final int T_JavaLangStringBuffer = 17; + final int T_JavaLangSystem = 18; + final int T_JavaLangError = 19; + final int T_JavaLangReflectConstructor = 20; + final int T_JavaLangThrowable = 21; + final int T_JavaLangNoClassDefError = 22; + final int T_JavaLangClassNotFoundException = 23; + final int T_JavaIoPrintStream = 24; + final int T_JavaLangException = 25; + + // wrapper types + final int T_JavaLangByte = 26; + final int T_JavaLangShort = 27; + final int T_JavaLangCharacter = 28; + final int T_JavaLangInteger = 29; + final int T_JavaLangLong = 30; + final int T_JavaLangFloat = 31; + final int T_JavaLangDouble = 32; + final int T_JavaLangBoolean = 33; + final int T_JavaLangVoid = 34; + + // 1.4 feature + final int T_JavaLangAssertionError = 35; + final int NoId = Integer.MAX_VALUE; + + // implicit conversions: to (note: booleans are integers at runtime) + final int Boolean2Int = T_boolean + (T_int << 4); + final int Boolean2String = T_boolean + (T_String << 4); + final int Boolean2Boolean = T_boolean + (T_boolean << 4); + final int Byte2Byte = T_byte + (T_byte << 4); + final int Byte2Short = T_byte + (T_short << 4); + final int Byte2Char = T_byte + (T_char << 4); + final int Byte2Int = T_byte + (T_int << 4); + final int Byte2Long = T_byte + (T_long << 4); + final int Byte2Float = T_byte + (T_float << 4); + final int Byte2Double = T_byte + (T_double << 4); + final int Byte2String = T_byte + (T_String << 4); + final int Short2Byte = T_short + (T_byte << 4); + final int Short2Short = T_short + (T_short << 4); + final int Short2Char = T_short + (T_char << 4); + final int Short2Int = T_short + (T_int << 4); + final int Short2Long = T_short + (T_long << 4); + final int Short2Float = T_short + (T_float << 4); + final int Short2Double = T_short + (T_double << 4); + final int Short2String = T_short + (T_String << 4); + final int Char2Byte = T_char + (T_byte << 4); + final int Char2Short = T_char + (T_short << 4); + final int Char2Char = T_char + (T_char << 4); + final int Char2Int = T_char + (T_int << 4); + final int Char2Long = T_char + (T_long << 4); + final int Char2Float = T_char + (T_float << 4); + final int Char2Double = T_char + (T_double << 4); + final int Char2String = T_char + (T_String << 4); + final int Int2Byte = T_int + (T_byte << 4); + final int Int2Short = T_int + (T_short << 4); + final int Int2Char = T_int + (T_char << 4); + final int Int2Int = T_int + (T_int << 4); + final int Int2Long = T_int + (T_long << 4); + final int Int2Float = T_int + (T_float << 4); + final int Int2Double = T_int + (T_double << 4); + final int Int2String = T_int + (T_String << 4); + final int Long2Byte = T_long + (T_byte << 4); + final int Long2Short = T_long + (T_short << 4); + final int Long2Char = T_long + (T_char << 4); + final int Long2Int = T_long + (T_int << 4); + final int Long2Long = T_long + (T_long << 4); + final int Long2Float = T_long + (T_float << 4); + final int Long2Double = T_long + (T_double << 4); + final int Long2String = T_long + (T_String << 4); + final int Float2Byte = T_float + (T_byte << 4); + final int Float2Short = T_float + (T_short << 4); + final int Float2Char = T_float + (T_char << 4); + final int Float2Int = T_float + (T_int << 4); + final int Float2Long = T_float + (T_long << 4); + final int Float2Float = T_float + (T_float << 4); + final int Float2Double = T_float + (T_double << 4); + final int Float2String = T_float + (T_String << 4); + final int Double2Byte = T_double + (T_byte << 4); + final int Double2Short = T_double + (T_short << 4); + final int Double2Char = T_double + (T_char << 4); + final int Double2Int = T_double + (T_int << 4); + final int Double2Long = T_double + (T_long << 4); + final int Double2Float = T_double + (T_float << 4); + final int Double2Double = T_double + (T_double << 4); + final int Double2String = T_double + (T_String << 4); + final int String2String = T_String + (T_String << 4); + final int Object2String = T_Object + (T_String << 4); + final int Null2String = T_null + (T_String << 4); + final int Object2Object = T_Object + (T_Object << 4); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/UnresolvedReferenceBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/UnresolvedReferenceBinding.java new file mode 100644 index 0000000..0a8f86a --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/UnresolvedReferenceBinding.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class UnresolvedReferenceBinding extends ReferenceBinding { + ReferenceBinding resolvedType; +UnresolvedReferenceBinding(char[][] compoundName, PackageBinding packageBinding) { + this.compoundName = compoundName; + this.fPackage = packageBinding; +} +String debugName() { + return toString(); +} +ReferenceBinding resolve(LookupEnvironment environment) { + if (resolvedType != null) return resolvedType; + + ReferenceBinding environmentType = fPackage.getType0(compoundName[compoundName.length - 1]); + if (environmentType == this) + environmentType = environment.askForType(compoundName); + if (environmentType != null && environmentType != this) { // could not resolve any better, error was already reported against it + resolvedType = environmentType; + environment.updateArrayCache(this, environmentType); + return environmentType; // when found, it replaces the unresolved type in the cache + } + + environment.problemReporter.isClassPathCorrect(compoundName, null); + return null; // will not get here since the above error aborts the compilation +} +public String toString() { + return "Unresolved type " + ((compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED"); //$NON-NLS-1$ //$NON-NLS-2$ +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/VariableBinding.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/VariableBinding.java new file mode 100644 index 0000000..be7363c --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/VariableBinding.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import net.sourceforge.phpdt.internal.compiler.impl.Constant; + +public abstract class VariableBinding extends Binding { + public int modifiers; + public TypeBinding type; + public char[] name; + public Constant constant; + public int id; // for flow-analysis (position in flowInfo bit vector) +public boolean isConstantValue() { + return constant != Constant.NotAConstant; +} +/* Answer true if the receiver is final and cannot be changed +*/ + +public final boolean isFinal() { + return (modifiers & AccFinal) != 0; +} +public char[] readableName() { + return name; +} +public String toString() { + String s = (type != null) ? type.debugName() : "UNDEFINED TYPE"; //$NON-NLS-1$ + s += " "; //$NON-NLS-1$ + s += (name != null) ? new String(name) : "UNNAMED FIELD"; //$NON-NLS-1$ + return s; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/NLSLine.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/NLSLine.java new file mode 100644 index 0000000..8164e49 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/NLSLine.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.parser; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import net.sourceforge.phpdt.internal.compiler.ast.StringLiteral; + + +public class NLSLine { + + private List elements; + + + public NLSLine() { + this.elements = new ArrayList(); + } + + /** + * Adds a NLS element to this line. + */ + public void add(StringLiteral element) { + this.elements.add(element); + } + + /** + * returns an Iterator over NLSElements + */ + public Iterator iterator() { + return this.elements.iterator(); + } + + public StringLiteral get(int index) { + return (StringLiteral) this.elements.get(index); + } + + public void set(int index, StringLiteral literal) { + this.elements.set(index, literal); + } + + public boolean exists(int index) { + return index >= 0 && index < this.elements.size(); + } + + public int size(){ + return this.elements.size(); + } + + public String toString() { + StringBuffer result= new StringBuffer(); + for (Iterator iter= iterator(); iter.hasNext(); ) { + result.append("\t"); //$NON-NLS-1$ + result.append(iter.next().toString()); + result.append("\n"); //$NON-NLS-1$ + } + return result.toString(); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/Parser.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/Parser.java new file mode 100644 index 0000000..d46b0a2 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/Parser.java @@ -0,0 +1,7453 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.parser; + +import net.sourceforge.phpdt.core.compiler.*; +import net.sourceforge.phpdt.core.compiler.InvalidInputException; +import net.sourceforge.phpdt.internal.compiler.*; +import net.sourceforge.phpdt.internal.compiler.env.*; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; +import net.sourceforge.phpdt.internal.compiler.util.*; + +import java.io.*; +import java.util.ArrayList; + +public class Parser implements BindingIds, ParserBasicInformation, ITerminalSymbols, CompilerModifiers, OperatorIds, TypeIds { + protected ProblemReporter problemReporter; + public int firstToken ; // handle for multiple parsing goals + public int lastAct ; //handle for multiple parsing goals + protected ReferenceContext referenceContext; + public int currentToken; + private int synchronizedBlockSourceStart; + + //error recovery management + protected int lastCheckPoint; + protected RecoveredElement currentElement; + public static boolean VERBOSE_RECOVERY = false; + protected boolean restartRecovery; + protected int listLength; // for recovering some incomplete list (interfaces, throws or parameters) + protected boolean hasReportedError; + protected int recoveredStaticInitializerStart; + protected int lastIgnoredToken, nextIgnoredToken; + protected int lastErrorEndPosition; + + // 1.4 feature + protected boolean assertMode = false; + + //internal data for the automat + protected final static int StackIncrement = 255; + protected int stateStackTop; + protected int[] stack = new int[StackIncrement]; + //scanner token + public Scanner scanner; + //ast stack + final static int AstStackIncrement = 100; + protected int astPtr; + protected AstNode[] astStack = new AstNode[AstStackIncrement]; + protected int astLengthPtr; + protected int[] astLengthStack; + public CompilationUnitDeclaration compilationUnit; /*the result from parse()*/ + AstNode [] noAstNodes = new AstNode[AstStackIncrement]; + //expression stack + final static int ExpressionStackIncrement = 100; + protected int expressionPtr; + protected Expression[] expressionStack = new Expression[ExpressionStackIncrement]; + protected int expressionLengthPtr; + protected int[] expressionLengthStack; + Expression [] noExpressions = new Expression[ExpressionStackIncrement]; + //identifiers stacks + protected int identifierPtr; + protected char[][] identifierStack; + protected int identifierLengthPtr; + protected int[] identifierLengthStack; + protected long[] identifierPositionStack; + //positions , dimensions , .... (what ever is int) ..... stack + protected int intPtr; + protected int[] intStack; + protected int endPosition; //accurate only when used ! (the start position is pushed into intStack while the end the current one) + protected int endStatementPosition; + protected int lParenPos,rParenPos; //accurate only when used ! + //modifiers dimensions nestedType etc....... + protected boolean optimizeStringLiterals =true; + protected int modifiers; + protected int modifiersSourceStart; + protected int nestedType, dimensions; + protected int[] nestedMethod; //the ptr is nestedType + protected int[] realBlockStack; + protected int realBlockPtr; + protected boolean diet = false; //tells the scanner to jump over some parts of the code/expressions like method bodies + protected int dietInt = 0; // if > 0 force the none-diet-parsing mode (even if diet if requested) [field parsing with anonymous inner classes...] + protected int[] variablesCounter; + //===DATA===DATA===DATA===DATA===DATA===DATA===// + public final static byte rhs[] = {0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,1,1,1,1,3,4,0,1,2,1,1,1,1, + 1,1,1,1,1,5,1,2,1,2,2,2,1,1,2, + 2,2,4,1,1,1,1,2,1,1,1,1,1,1,1, + 1,1,1,1,2,3,3,2,2,1,3,1,3,1,2, + 1,1,1,3,0,3,1,1,1,1,1,1,1,4,1, + 3,3,7,0,0,0,0,0,2,1,1,1,2,2,4, + 4,5,4,4,2,1,2,3,3,1,3,3,1,3,1, + 4,0,2,1,2,2,4,1,1,2,5,5,7,7,7, + 7,2,2,3,2,2,3,1,2,1,2,1,1,2,2, + 1,1,1,1,1,3,3,4,1,3,4,0,1,2,1, + 1,1,1,2,3,4,0,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,3,3,2,1,1,1,1,1,1,1,5,7,7,6, + 2,3,3,4,1,2,2,1,2,3,2,5,5,7,9, + 9,1,1,1,1,3,3,5,2,3,2,3,3,3,5, + 1,3,4,1,2,5,2,1,1,1,1,1,1,3,1, + 1,3,3,3,3,3,1,1,5,6,8,7,2,0,2, + 0,1,3,4,4,1,2,3,2,1,1,2,2,3,3, + 4,6,6,4,4,1,1,1,1,2,2,0,1,1,3, + 3,1,3,3,1,3,3,1,5,5,4,1,3,3,3, + 1,3,3,1,3,3,3,1,3,3,3,3,3,1,3, + 3,1,3,1,3,1,3,1,3,1,3,1,5,1,1, + 3,3,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,0,1,0,1,0,1,0,1,0,1, + 0,1,0,2,0,1,0,1,0,1,0,1,0,1,0, + 1,0,1,0,2,0,0,1,0,1,0,1,0,1,0, + 1 + }; + + + public static char asb[] = null; + public static char asr[] = null; + public static char symbol_index[] = null; + private static final String UNEXPECTED_EOF = "Unexpected End Of File" ; //$NON-NLS-1$ + + public final static String name[] = { null, + "++",//$NON-NLS-1$ + "--",//$NON-NLS-1$ + "==",//$NON-NLS-1$ + "<=",//$NON-NLS-1$ + ">=",//$NON-NLS-1$ + "!=",//$NON-NLS-1$ + "<<",//$NON-NLS-1$ + ">>",//$NON-NLS-1$ + ">>>",//$NON-NLS-1$ + "+=",//$NON-NLS-1$ + "-=",//$NON-NLS-1$ + "*=",//$NON-NLS-1$ + "/=",//$NON-NLS-1$ + "&=",//$NON-NLS-1$ + "|=",//$NON-NLS-1$ + "^=",//$NON-NLS-1$ + "%=",//$NON-NLS-1$ + "<<=",//$NON-NLS-1$ + ">>=",//$NON-NLS-1$ + ">>>=",//$NON-NLS-1$ + "||",//$NON-NLS-1$ + "&&",//$NON-NLS-1$ + "+",//$NON-NLS-1$ + "-",//$NON-NLS-1$ + "!",//$NON-NLS-1$ + "%",//$NON-NLS-1$ + "^",//$NON-NLS-1$ + "&",//$NON-NLS-1$ + "*",//$NON-NLS-1$ + "|",//$NON-NLS-1$ + "~",//$NON-NLS-1$ + "/",//$NON-NLS-1$ + ">",//$NON-NLS-1$ + "<",//$NON-NLS-1$ + "(",//$NON-NLS-1$ + ")",//$NON-NLS-1$ + "{",//$NON-NLS-1$ + "}",//$NON-NLS-1$ + "[",//$NON-NLS-1$ + "]",//$NON-NLS-1$ + ";",//$NON-NLS-1$ + "?",//$NON-NLS-1$ + ":",//$NON-NLS-1$ + ",",//$NON-NLS-1$ + ".",//$NON-NLS-1$ + "=",//$NON-NLS-1$ + "",//$NON-NLS-1$ + "$empty",//$NON-NLS-1$ + "Identifier",//$NON-NLS-1$ + "abstract",//$NON-NLS-1$ + "assert",//$NON-NLS-1$ + "boolean",//$NON-NLS-1$ + "break",//$NON-NLS-1$ + "byte",//$NON-NLS-1$ + "case",//$NON-NLS-1$ + "catch",//$NON-NLS-1$ + "char",//$NON-NLS-1$ + "class",//$NON-NLS-1$ + "continue",//$NON-NLS-1$ + "default",//$NON-NLS-1$ + "do",//$NON-NLS-1$ + "double",//$NON-NLS-1$ + "else",//$NON-NLS-1$ + "extends",//$NON-NLS-1$ + "false",//$NON-NLS-1$ + "final",//$NON-NLS-1$ + "finally",//$NON-NLS-1$ + "float",//$NON-NLS-1$ + "for",//$NON-NLS-1$ + "if",//$NON-NLS-1$ + "implements",//$NON-NLS-1$ + "import",//$NON-NLS-1$ + "instanceof",//$NON-NLS-1$ + "int",//$NON-NLS-1$ + "interface",//$NON-NLS-1$ + "long",//$NON-NLS-1$ + "native",//$NON-NLS-1$ + "new",//$NON-NLS-1$ + "null",//$NON-NLS-1$ + "package",//$NON-NLS-1$ + "private",//$NON-NLS-1$ + "protected",//$NON-NLS-1$ + "public",//$NON-NLS-1$ + "return",//$NON-NLS-1$ + "short",//$NON-NLS-1$ + "static",//$NON-NLS-1$ + "strictfp",//$NON-NLS-1$ + "super",//$NON-NLS-1$ + "switch",//$NON-NLS-1$ + "synchronized",//$NON-NLS-1$ + "this",//$NON-NLS-1$ + "throw",//$NON-NLS-1$ + "throws",//$NON-NLS-1$ + "transient",//$NON-NLS-1$ + "true",//$NON-NLS-1$ + "try",//$NON-NLS-1$ + "void",//$NON-NLS-1$ + "volatile",//$NON-NLS-1$ + "while",//$NON-NLS-1$ + "IntegerLiteral",//$NON-NLS-1$ + "LongLiteral",//$NON-NLS-1$ + "FloatingPointLiteral",//$NON-NLS-1$ + "DoubleLiteral",//$NON-NLS-1$ + "CharacterLiteral",//$NON-NLS-1$ + "StringLiteral",//$NON-NLS-1$ + UNEXPECTED_EOF, + "Invalid Character",//$NON-NLS-1$ + "Goal",//$NON-NLS-1$ + "MethodBody",//$NON-NLS-1$ + "ConstructorBody",//$NON-NLS-1$ + "StaticInitializer",//$NON-NLS-1$ + "Initializer",//$NON-NLS-1$ + "Headers",//$NON-NLS-1$ + "BlockStatements",//$NON-NLS-1$ + "MethodPushModifiersHeader",//$NON-NLS-1$ + "CatchHeader",//$NON-NLS-1$ + "FieldDeclaration",//$NON-NLS-1$ + "ImportDeclaration",//$NON-NLS-1$ + "PackageDeclaration",//$NON-NLS-1$ + "TypeDeclaration",//$NON-NLS-1$ + "GenericMethodDeclaration",//$NON-NLS-1$ + "ClassBodyDeclaration",//$NON-NLS-1$ + "Expression",//$NON-NLS-1$ + "Type",//$NON-NLS-1$ + "PrimitiveType",//$NON-NLS-1$ + "ReferenceType",//$NON-NLS-1$ + "ClassOrInterfaceType",//$NON-NLS-1$ + "ArrayType",//$NON-NLS-1$ + "Name",//$NON-NLS-1$ + "Dims",//$NON-NLS-1$ + "ClassType",//$NON-NLS-1$ + "SimpleName",//$NON-NLS-1$ + "Header",//$NON-NLS-1$ + "ClassHeader",//$NON-NLS-1$ + "InterfaceHeader",//$NON-NLS-1$ + "MethodHeader",//$NON-NLS-1$ + "ConstructorHeader",//$NON-NLS-1$ + "FormalParameter",//$NON-NLS-1$ + "ImportDeclarations",//$NON-NLS-1$ + "TypeDeclarations",//$NON-NLS-1$ + "PackageDeclarationName",//$NON-NLS-1$ + "SingleTypeImportDeclarationName",//$NON-NLS-1$ + "TypeImportOnDemandDeclarationName",//$NON-NLS-1$ + "Modifiers",//$NON-NLS-1$ + "Modifier",//$NON-NLS-1$ + "ClassBody",//$NON-NLS-1$ + "ClassHeaderName",//$NON-NLS-1$ + "InterfaceTypeList",//$NON-NLS-1$ + "InterfaceType",//$NON-NLS-1$ + "ClassBodyDeclarations",//$NON-NLS-1$ + "Block",//$NON-NLS-1$ + "VariableDeclarators",//$NON-NLS-1$ + "VariableDeclarator",//$NON-NLS-1$ + "VariableDeclaratorId",//$NON-NLS-1$ + "VariableInitializer",//$NON-NLS-1$ + "ArrayInitializer",//$NON-NLS-1$ + "MethodHeaderName",//$NON-NLS-1$ + "MethodHeaderParameters",//$NON-NLS-1$ + "MethodPushModifiersHeaderName",//$NON-NLS-1$ + "ClassTypeList",//$NON-NLS-1$ + "ConstructorHeaderName",//$NON-NLS-1$ + "FormalParameterList",//$NON-NLS-1$ + "ClassTypeElt",//$NON-NLS-1$ + "StaticOnly",//$NON-NLS-1$ + "ExplicitConstructorInvocation",//$NON-NLS-1$ + "Primary",//$NON-NLS-1$ + "InterfaceBody",//$NON-NLS-1$ + "InterfaceHeaderName",//$NON-NLS-1$ + "InterfaceMemberDeclarations",//$NON-NLS-1$ + "InterfaceMemberDeclaration",//$NON-NLS-1$ + "VariableInitializers",//$NON-NLS-1$ + "BlockStatement",//$NON-NLS-1$ + "Statement",//$NON-NLS-1$ + "LocalVariableDeclaration",//$NON-NLS-1$ + "StatementWithoutTrailingSubstatement",//$NON-NLS-1$ + "StatementNoShortIf",//$NON-NLS-1$ + "StatementExpression",//$NON-NLS-1$ + "PostIncrementExpression",//$NON-NLS-1$ + "PostDecrementExpression",//$NON-NLS-1$ + "MethodInvocation",//$NON-NLS-1$ + "ClassInstanceCreationExpression",//$NON-NLS-1$ + "SwitchBlock",//$NON-NLS-1$ + "SwitchBlockStatements",//$NON-NLS-1$ + "SwitchLabels",//$NON-NLS-1$ + "SwitchBlockStatement",//$NON-NLS-1$ + "SwitchLabel",//$NON-NLS-1$ + "ConstantExpression",//$NON-NLS-1$ + "StatementExpressionList",//$NON-NLS-1$ + "OnlySynchronized",//$NON-NLS-1$ + "Catches",//$NON-NLS-1$ + "Finally",//$NON-NLS-1$ + "CatchClause",//$NON-NLS-1$ + "PushLPAREN",//$NON-NLS-1$ + "PushRPAREN",//$NON-NLS-1$ + "PrimaryNoNewArray",//$NON-NLS-1$ + "FieldAccess",//$NON-NLS-1$ + "ArrayAccess",//$NON-NLS-1$ + "ClassInstanceCreationExpressionName",//$NON-NLS-1$ + "ArgumentList",//$NON-NLS-1$ + "DimWithOrWithOutExprs",//$NON-NLS-1$ + "DimWithOrWithOutExpr",//$NON-NLS-1$ + "DimsLoop",//$NON-NLS-1$ + "OneDimLoop",//$NON-NLS-1$ + "PostfixExpression",//$NON-NLS-1$ + "UnaryExpression",//$NON-NLS-1$ + "UnaryExpressionNotPlusMinus",//$NON-NLS-1$ + "MultiplicativeExpression",//$NON-NLS-1$ + "AdditiveExpression",//$NON-NLS-1$ + "ShiftExpression",//$NON-NLS-1$ + "RelationalExpression",//$NON-NLS-1$ + "EqualityExpression",//$NON-NLS-1$ + "AndExpression",//$NON-NLS-1$ + "ExclusiveOrExpression",//$NON-NLS-1$ + "InclusiveOrExpression",//$NON-NLS-1$ + "ConditionalAndExpression",//$NON-NLS-1$ + "ConditionalOrExpression",//$NON-NLS-1$ + "ConditionalExpression",//$NON-NLS-1$ + "AssignmentExpression",//$NON-NLS-1$ + "LeftHandSide",//$NON-NLS-1$ + "AssignmentOperator"//$NON-NLS-1$ + }; + + public static short check_table[] = null; + public static char lhs[] = null; + public static char action[] = lhs; + private final static String FILEPREFIX = "parser"; //$NON-NLS-1$ + + static { + try{ + initTables(); + } catch(java.io.IOException ex){ + throw new ExceptionInInitializerError(ex.getMessage()); + } + } + + public static final int RoundBracket = 0; + public static final int SquareBracket = 1; + public static final int CurlyBracket = 2; + public static final int BracketKinds = 3; + +public Parser(ProblemReporter problemReporter, boolean optimizeStringLiterals, boolean assertMode) { + + this.problemReporter = problemReporter; + this.optimizeStringLiterals = optimizeStringLiterals; + this.assertMode = assertMode; + this.initializeScanner(); + astLengthStack = new int[50]; + expressionLengthStack = new int[30]; + intStack = new int[50]; + identifierStack = new char[30][]; + identifierLengthStack = new int[30]; + nestedMethod = new int[30]; + realBlockStack = new int[30]; + identifierPositionStack = new long[30]; + variablesCounter = new int[30]; +} +/** + * + * INTERNAL USE-ONLY + */ +protected void adjustInterfaceModifiers() { + intStack[intPtr - 1] |= AccInterface; +} +public final void arrayInitializer(int length) { + //length is the size of the array Initializer + //expressionPtr points on the last elt of the arrayInitializer + //i.e. it has not been decremented yet. + + ArrayInitializer ai = new ArrayInitializer(); + if (length != 0) { + expressionPtr -= length; + System.arraycopy(expressionStack, expressionPtr + 1, ai.expressions = new Expression[length], 0, length); + } + pushOnExpressionStack(ai); + //positionning + ai.sourceEnd = endStatementPosition; + int searchPosition = length == 0 ? endPosition : ai.expressions[0].sourceStart; + try { + //does not work with comments(that contain '{') nor '{' describes as a unicode.... + while (scanner.source[--searchPosition] != '{') { + } + } catch (IndexOutOfBoundsException ex) { + //should never occur (except for strange cases like whose describe above) + searchPosition = (length == 0 ? endPosition : ai.expressions[0].sourceStart) - 1; + } + ai.sourceStart = searchPosition; +} +protected static int asi(int state) { + + return asb[original_state(state)]; +} +protected void blockReal() { + // See consumeLocalVariableDeclarationStatement in case of change: duplicated code + // increment the amount of declared variables for this block + realBlockStack[realBlockPtr]++; +} +private final static void buildFileFor(String filename, String tag, String[] tokens, boolean isShort) throws java.io.IOException { + + //transform the String tokens into chars before dumping then into file + + int i = 0; + //read upto the tag + while (!tokens[i++].equals(tag)) {} + //read upto the } + char[] chars = new char[tokens.length]; //can't be bigger + int ic = 0; + String token; + while (!(token = tokens[i++]).equals("}")) { //$NON-NLS-1$ + int c = Integer.parseInt(token); + if (isShort) + c += 32768; + chars[ic++] = (char) c; + } + + //resize + System.arraycopy(chars, 0, chars = new char[ic], 0, ic); + + buildFileForTable(filename, chars); +} +private final static void buildFileForTable(String filename, char[] chars) throws java.io.IOException { + + byte[] bytes = new byte[chars.length * 2]; + for (int i = 0; i < chars.length; i++) { + bytes[2 * i] = (byte) (chars[i] >>> 8); + bytes[2 * i + 1] = (byte) (chars[i] & 0xFF); + } + + java.io.FileOutputStream stream = new java.io.FileOutputStream(filename); + stream.write(bytes); + stream.close(); + System.out.println(filename + " creation complete"); //$NON-NLS-1$ +} +public final static void buildFilesFromLPG(String dataFilename) throws java.io.IOException { + + //RUN THIS METHOD TO GENERATE PARSER*.RSC FILES + + //build from the lpg javadcl.java files that represents the parser tables + //lhs check_table asb asr symbol_index + + //[org.eclipse.jdt.internal.compiler.parser.Parser.buildFilesFromLPG("d:/leapfrog/grammar/javadcl.java")] + + char[] contents = new char[] {}; + try { + contents = Util.getFileCharContent(new File(dataFilename), null); + } catch (IOException ex) { + System.out.println(Util.bind("parser.incorrectPath")); //$NON-NLS-1$ + return; + } + java.util.StringTokenizer st = + new java.util.StringTokenizer(new String(contents), " \t\n\r[]={,;"); //$NON-NLS-1$ + String[] tokens = new String[st.countTokens()]; + int i = 0; + while (st.hasMoreTokens()) { + tokens[i++] = st.nextToken(); + } + final String prefix = FILEPREFIX; + i = 0; + buildFileFor(prefix + (++i) + ".rsc", "lhs", tokens, false); //$NON-NLS-2$ //$NON-NLS-1$ + buildFileFor(prefix + (++i) + ".rsc", "check_table", tokens, true); //$NON-NLS-2$ //$NON-NLS-1$ + buildFileFor(prefix + (++i) + ".rsc", "asb", tokens, false); //$NON-NLS-2$ //$NON-NLS-1$ + buildFileFor(prefix + (++i) + ".rsc", "asr", tokens, false); //$NON-NLS-2$ //$NON-NLS-1$ + buildFileFor(prefix + (++i) + ".rsc", "symbol_index", tokens, false); //$NON-NLS-2$ //$NON-NLS-1$ + System.out.println(Util.bind("parser.moveFiles")); //$NON-NLS-1$ +} +/* + * Build initial recovery state. + * Recovery state is inferred from the current state of the parser (reduced node stack). + */ +public RecoveredElement buildInitialRecoveryState(){ + + /* initialize recovery by retrieving available reduced nodes + * also rebuild bracket balance + */ + lastCheckPoint = 0; + + RecoveredElement element = null; + if (referenceContext instanceof CompilationUnitDeclaration){ + element = new RecoveredUnit(compilationUnit, 0, this); + + /* ignore current stack state, since restarting from the beginnning + since could not trust simple brace count */ + if (true){ // experimenting restart recovery from scratch + compilationUnit.currentPackage = null; + compilationUnit.imports = null; + compilationUnit.types = null; + currentToken = 0; + listLength = 0; + return element; + } + if (compilationUnit.currentPackage != null){ + lastCheckPoint = compilationUnit.currentPackage.declarationSourceEnd+1; + } + if (compilationUnit.imports != null){ + lastCheckPoint = compilationUnit.imports[compilationUnit.imports.length -1].declarationSourceEnd+1; + } + } else { + if (referenceContext instanceof AbstractMethodDeclaration){ + element = new RecoveredMethod((AbstractMethodDeclaration) referenceContext, null, 0, this); + lastCheckPoint = ((AbstractMethodDeclaration) referenceContext).bodyStart; + } else { + /* Initializer bodies are parsed in the context of the type declaration, we must thus search it inside */ + if (referenceContext instanceof TypeDeclaration){ + TypeDeclaration type = (TypeDeclaration) referenceContext; + for (int i = 0; i < type.fields.length; i++){ + FieldDeclaration field = type.fields[i]; + if (!field.isField() + && field.declarationSourceStart <= scanner.initialPosition + && scanner.initialPosition <= field.declarationSourceEnd + && scanner.eofPosition <= field.declarationSourceEnd+1){ + element = new RecoveredInitializer((Initializer) field, null, 1, this); + lastCheckPoint = field.declarationSourceStart; + break; + } + } + } + } + } + + if (element == null) return element; + + for(int i = 0; i <= astPtr; i++){ + AstNode node = astStack[i]; + if (node instanceof AbstractMethodDeclaration){ + AbstractMethodDeclaration method = (AbstractMethodDeclaration) node; + if (method.declarationSourceEnd == 0){ + element = element.add(method, 0); + lastCheckPoint = method.bodyStart; + } else { + element = element.add(method, 0); + lastCheckPoint = method.declarationSourceEnd + 1; + } + continue; + } + if (node instanceof Initializer){ + Initializer initializer = (Initializer) node; + if (initializer.declarationSourceEnd == 0){ + element = element.add(initializer, 1); + lastCheckPoint = initializer.bodyStart; + } else { + element = element.add(initializer, 0); + lastCheckPoint = initializer.declarationSourceEnd + 1; + } + continue; + } + if (node instanceof FieldDeclaration){ + FieldDeclaration field = (FieldDeclaration) node; + if (field.declarationSourceEnd == 0){ + element = element.add(field, 0); + if (field.initialization == null){ + lastCheckPoint = field.sourceEnd + 1; + } else { + lastCheckPoint = field.initialization.sourceEnd + 1; + } + } else { + element = element.add(field, 0); + lastCheckPoint = field.declarationSourceEnd + 1; + } + continue; + } + if (node instanceof TypeDeclaration){ + TypeDeclaration type = (TypeDeclaration) node; + if (type.declarationSourceEnd == 0){ + element = element.add(type, 0); + lastCheckPoint = type.bodyStart; + } else { + element = element.add(type, 0); + lastCheckPoint = type.declarationSourceEnd + 1; + } + continue; + } + if (node instanceof ImportReference){ + ImportReference importRef = (ImportReference) node; + element = element.add(importRef, 0); + lastCheckPoint = importRef.declarationSourceEnd + 1; + } + } + return element; +} +protected static short check(int i) { + return check_table[i - (NUM_RULES + 1)]; +} +/* + * Reconsider the entire source looking for inconsistencies in {} () [] + */ +public boolean checkAndReportBracketAnomalies(ProblemReporter problemReporter) { + + scanner.wasAcr = false; + boolean anomaliesDetected = false; + try { + char[] source = scanner.source; + int[] leftCount = {0, 0, 0}; + int[] rightCount = {0, 0, 0}; + int[] depths = {0, 0, 0}; + int[][] leftPositions = new int[][] {new int[10], new int[10], new int[10]}; + int[][] leftDepths = new int[][] {new int[10], new int[10], new int[10]}; + int[][] rightPositions = new int[][] {new int[10], new int[10], new int[10]}; + int[][] rightDepths = new int[][] {new int[10], new int[10], new int[10]}; + scanner.currentPosition = scanner.initialPosition; //starting point (first-zero-based char) + while (scanner.currentPosition < scanner.eofPosition) { //loop for jumping over comments + try { + // ---------Consume white space and handles startPosition--------- + boolean isWhiteSpace; + do { + scanner.startPosition = scanner.currentPosition; + if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) { + isWhiteSpace = scanner.jumpOverUnicodeWhiteSpace(); + } else { + if (scanner.recordLineSeparator && ((scanner.currentCharacter == '\r') || (scanner.currentCharacter == '\n'))) { + if (scanner.lineEnds[scanner.linePtr] < scanner.startPosition) { + // only record line positions we have not recorded yet + scanner.pushLineSeparator(); + } + } + isWhiteSpace = Character.isWhitespace(scanner.currentCharacter); + } + } while (isWhiteSpace && (scanner.currentPosition < scanner.eofPosition)); + + // -------consume token until } is found--------- + + switch (scanner.currentCharacter) { + case '{' : + { + int index = leftCount[CurlyBracket] ++; + if (index == leftPositions[CurlyBracket].length) { + System.arraycopy(leftPositions[CurlyBracket], 0, (leftPositions[CurlyBracket] = new int[index * 2]), 0, index); + System.arraycopy(leftDepths[CurlyBracket], 0, (leftDepths[CurlyBracket] = new int[index * 2]), 0, index); + } + leftPositions[CurlyBracket][index] = scanner.startPosition; + leftDepths[CurlyBracket][index] = depths[CurlyBracket] ++; + } + break; + case '}' : + { + int index = rightCount[CurlyBracket] ++; + if (index == rightPositions[CurlyBracket].length) { + System.arraycopy(rightPositions[CurlyBracket], 0, (rightPositions[CurlyBracket] = new int[index * 2]), 0, index); + System.arraycopy(rightDepths[CurlyBracket], 0, (rightDepths[CurlyBracket] = new int[index * 2]), 0, index); + } + rightPositions[CurlyBracket][index] = scanner.startPosition; + rightDepths[CurlyBracket][index] = --depths[CurlyBracket]; + } + break; + case '(' : + { + int index = leftCount[RoundBracket] ++; + if (index == leftPositions[RoundBracket].length) { + System.arraycopy(leftPositions[RoundBracket], 0, (leftPositions[RoundBracket] = new int[index * 2]), 0, index); + System.arraycopy(leftDepths[RoundBracket], 0, (leftDepths[RoundBracket] = new int[index * 2]), 0, index); + } + leftPositions[RoundBracket][index] = scanner.startPosition; + leftDepths[RoundBracket][index] = depths[RoundBracket] ++; + } + break; + case ')' : + { + int index = rightCount[RoundBracket] ++; + if (index == rightPositions[RoundBracket].length) { + System.arraycopy(rightPositions[RoundBracket], 0, (rightPositions[RoundBracket] = new int[index * 2]), 0, index); + System.arraycopy(rightDepths[RoundBracket], 0, (rightDepths[RoundBracket] = new int[index * 2]), 0, index); + } + rightPositions[RoundBracket][index] = scanner.startPosition; + rightDepths[RoundBracket][index] = --depths[RoundBracket]; + } + break; + case '[' : + { + int index = leftCount[SquareBracket] ++; + if (index == leftPositions[SquareBracket].length) { + System.arraycopy(leftPositions[SquareBracket], 0, (leftPositions[SquareBracket] = new int[index * 2]), 0, index); + System.arraycopy(leftDepths[SquareBracket], 0, (leftDepths[SquareBracket] = new int[index * 2]), 0, index); + } + leftPositions[SquareBracket][index] = scanner.startPosition; + leftDepths[SquareBracket][index] = depths[SquareBracket] ++; + } + break; + case ']' : + { + int index = rightCount[SquareBracket] ++; + if (index == rightPositions[SquareBracket].length) { + System.arraycopy(rightPositions[SquareBracket], 0, (rightPositions[SquareBracket] = new int[index * 2]), 0, index); + System.arraycopy(rightDepths[SquareBracket], 0, (rightDepths[SquareBracket] = new int[index * 2]), 0, index); + } + rightPositions[SquareBracket][index] = scanner.startPosition; + rightDepths[SquareBracket][index] = --depths[SquareBracket]; + } + break; + case '\'' : + { + if (scanner.getNextChar('\\')) { + scanner.scanEscapeCharacter(); + } else { // consume next character + scanner.unicodeAsBackSlash = false; + if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) { + scanner.getNextUnicodeChar(); + } else { + if (scanner.withoutUnicodePtr != 0) { + scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = scanner.currentCharacter; + } + } + } + scanner.getNextChar('\''); + break; + } + case '"' : // consume next character + scanner.unicodeAsBackSlash = false; + if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) { + scanner.getNextUnicodeChar(); + } else { + if (scanner.withoutUnicodePtr != 0) { + scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = scanner.currentCharacter; + } + } + while (scanner.currentCharacter != '"') { + if (scanner.currentCharacter == '\r') { + if (source[scanner.currentPosition] == '\n') + scanner.currentPosition++; + break; // the string cannot go further that the line + } + if (scanner.currentCharacter == '\n') { + break; // the string cannot go further that the line + } + if (scanner.currentCharacter == '\\') { + scanner.scanEscapeCharacter(); + } + // consume next character + scanner.unicodeAsBackSlash = false; + if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) { + scanner.getNextUnicodeChar(); + } else { + if (scanner.withoutUnicodePtr != 0) { + scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = scanner.currentCharacter; + } + } + } + break; + case '/' : + { + int test; + if ((test = scanner.getNextChar('/', '*')) == 0) { //line comment + //get the next char + if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + scanner.currentPosition++; + while (source[scanner.currentPosition] == 'u') { + scanner.currentPosition++; + } + if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c1 < 0 || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c2 < 0 || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c3 < 0 || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c4 < 0) { //error don't care of the value + scanner.currentCharacter = 'A'; + } //something different from \n and \r + else { + scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + } + while (scanner.currentCharacter != '\r' && scanner.currentCharacter != '\n') { + //get the next char + scanner.startPosition = scanner.currentPosition; + if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + scanner.currentPosition++; + while (source[scanner.currentPosition] == 'u') { + scanner.currentPosition++; + } + if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c1 < 0 || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c2 < 0 || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c3 < 0 || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c4 < 0) { //error don't care of the value + scanner.currentCharacter = 'A'; + } //something different from \n and \r + else { + scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + } + } + if (scanner.recordLineSeparator && ((scanner.currentCharacter == '\r') || (scanner.currentCharacter == '\n'))) { + if (scanner.lineEnds[scanner.linePtr] < scanner.startPosition) { + // only record line positions we have not recorded yet + scanner.pushLineSeparator(); + } + } + break; + } + if (test > 0) { //traditional and annotation comment + boolean star = false; + // consume next character + scanner.unicodeAsBackSlash = false; + if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) { + scanner.getNextUnicodeChar(); + } else { + if (scanner.withoutUnicodePtr != 0) { + scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = scanner.currentCharacter; + } + } + if (scanner.currentCharacter == '*') { + star = true; + } + //get the next char + if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + scanner.currentPosition++; + while (source[scanner.currentPosition] == 'u') { + scanner.currentPosition++; + } + if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c1 < 0 || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c2 < 0 || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c3 < 0 || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c4 < 0) { //error don't care of the value + scanner.currentCharacter = 'A'; + } //something different from * and / + else { + scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + } + //loop until end of comment */ + while ((scanner.currentCharacter != '/') || (!star)) { + star = scanner.currentCharacter == '*'; + //get next char + if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + scanner.currentPosition++; + while (source[scanner.currentPosition] == 'u') { + scanner.currentPosition++; + } + if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c1 < 0 || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c2 < 0 || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c3 < 0 || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15 || c4 < 0) { //error don't care of the value + scanner.currentCharacter = 'A'; + } //something different from * and / + else { + scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + } + } + break; + } + break; + } + default : + if (Character.isJavaIdentifierStart(scanner.currentCharacter)) { + scanner.scanIdentifierOrKeyword(); + break; + } + if (Character.isDigit(scanner.currentCharacter)) { + scanner.scanNumber(false); + break; + } + } + //-----------------end switch while try-------------------- + } catch (IndexOutOfBoundsException e) { + break; // read until EOF + } catch (InvalidInputException e) { + return false; // no clue + } + } + if (scanner.recordLineSeparator) { + compilationUnit.compilationResult.lineSeparatorPositions = scanner.getLineEnds(); + } + + // check placement anomalies against other kinds of brackets + for (int kind = 0; kind < BracketKinds; kind++) { + for (int leftIndex = leftCount[kind] - 1; leftIndex >= 0; leftIndex--) { + int start = leftPositions[kind][leftIndex]; // deepest first + // find matching closing bracket + int depth = leftDepths[kind][leftIndex]; + int end = -1; + for (int i = 0; i < rightCount[kind]; i++) { + int pos = rightPositions[kind][i]; + // want matching bracket further in source with same depth + if ((pos > start) && (depth == rightDepths[kind][i])) { + end = pos; + break; + } + } + if (end < 0) { // did not find a good closing match + problemReporter.unmatchedBracket(start, referenceContext, compilationUnit.compilationResult); + return true; + } + // check if even number of opening/closing other brackets in between this pair of brackets + int balance = 0; + for (int otherKind = 0;(balance == 0) && (otherKind < BracketKinds); otherKind++) { + for (int i = 0; i < leftCount[otherKind]; i++) { + int pos = leftPositions[otherKind][i]; + if ((pos > start) && (pos < end)) + balance++; + } + for (int i = 0; i < rightCount[otherKind]; i++) { + int pos = rightPositions[otherKind][i]; + if ((pos > start) && (pos < end)) + balance--; + } + if (balance != 0) { + problemReporter.unmatchedBracket(start, referenceContext, compilationUnit.compilationResult); //bracket anomaly + return true; + } + } + } + // too many opening brackets ? + for (int i = rightCount[kind]; i < leftCount[kind]; i++) { + anomaliesDetected = true; + problemReporter.unmatchedBracket(leftPositions[kind][leftCount[kind] - i - 1], referenceContext, compilationUnit.compilationResult); + } + // too many closing brackets ? + for (int i = leftCount[kind]; i < rightCount[kind]; i++) { + anomaliesDetected = true; + problemReporter.unmatchedBracket(rightPositions[kind][i], referenceContext, compilationUnit.compilationResult); + } + if (anomaliesDetected) return true; + } + + return anomaliesDetected; + } catch (ArrayStoreException e) { // jdk1.2.2 jit bug + return anomaliesDetected; + } catch (NullPointerException e) { // jdk1.2.2 jit bug + return anomaliesDetected; + } +} +public final void checkAndSetModifiers(int flag){ + /*modify the current modifiers buffer. + When the startPosition of the modifiers is 0 + it means that the modifier being parsed is the first + of a list of several modifiers. The startPosition + is zeroed when a copy of modifiers-buffer is push + onto the astStack. */ + + if ((modifiers & flag) != 0){ // duplicate modifier + modifiers |= AccAlternateModifierProblem; + } + modifiers |= flag; + + if (modifiersSourceStart < 0) modifiersSourceStart = scanner.startPosition; +} +public void checkAnnotation() { + + boolean deprecated = false; + boolean checkDeprecated = false; + int lastAnnotationIndex = -1; + + //since jdk1.2 look only in the last java doc comment... + found : for (lastAnnotationIndex = scanner.commentPtr; lastAnnotationIndex >= 0; lastAnnotationIndex--){ + //look for @deprecated into the first javadoc comment preceeding the declaration + int commentSourceStart = scanner.commentStarts[lastAnnotationIndex]; + // javadoc only (non javadoc comment have negative end positions.) + if (modifiersSourceStart != -1 && modifiersSourceStart < commentSourceStart) { + continue; + } + if (scanner.commentStops[lastAnnotationIndex] < 0) { + break found; + } + checkDeprecated = true; + int commentSourceEnd = scanner.commentStops[lastAnnotationIndex] - 1; //stop is one over + char[] comment = scanner.source; + + for (int i = commentSourceStart + 3; i < commentSourceEnd - 10; i++) { + if ((comment[i] == '@') + && (comment[i + 1] == 'd') + && (comment[i + 2] == 'e') + && (comment[i + 3] == 'p') + && (comment[i + 4] == 'r') + && (comment[i + 5] == 'e') + && (comment[i + 6] == 'c') + && (comment[i + 7] == 'a') + && (comment[i + 8] == 't') + && (comment[i + 9] == 'e') + && (comment[i + 10] == 'd')) { + // ensure the tag is properly ended: either followed by a space, a tab, line end or asterisk. + int nextPos = i+11; + deprecated = (comment[nextPos] == ' ') || (comment[nextPos] == '\t') || (comment[nextPos] == '\n') || (comment[nextPos] == '\r') || (comment[nextPos] == '*'); + break found; + } + } + break found; + } + if (deprecated) { + checkAndSetModifiers(AccDeprecated); + } + // modify the modifier source start to point at the first comment + if (lastAnnotationIndex >= 0 && checkDeprecated) { + modifiersSourceStart = scanner.commentStarts[lastAnnotationIndex]; + } +} +protected void classInstanceCreation(boolean alwaysQualified) { + // ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt + + // ClassBodyopt produces a null item on the astStak if it produces NO class body + // An empty class body produces a 0 on the length stack..... + + AllocationExpression alloc; + int length; + if (((length = astLengthStack[astLengthPtr--]) == 1) + && (astStack[astPtr] == null)) { + //NO ClassBody + astPtr--; + if (alwaysQualified) { + alloc = new QualifiedAllocationExpression(); + } else { + alloc = new AllocationExpression(); + } + alloc.sourceEnd = endPosition; //the position has been stored explicitly + + if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) { + expressionPtr -= length; + System.arraycopy( + expressionStack, + expressionPtr + 1, + alloc.arguments = new Expression[length], + 0, + length); + } + alloc.type = getTypeReference(0); + //the default constructor with the correct number of argument + //will be created and added by the TC (see createsInternalConstructorWithBinding) + alloc.sourceStart = intStack[intPtr--]; + pushOnExpressionStack(alloc); + } else { + dispatchDeclarationInto(length); + AnonymousLocalTypeDeclaration anonymousTypeDeclaration = (AnonymousLocalTypeDeclaration) astStack[astPtr]; + anonymousTypeDeclaration.declarationSourceEnd = endStatementPosition; + anonymousTypeDeclaration.bodyEnd = endStatementPosition; + if (anonymousTypeDeclaration.allocation != null) { + anonymousTypeDeclaration.allocation.sourceEnd = endStatementPosition; + } + astPtr--; + astLengthPtr--; + + // mark fields and initializer with local type mark if needed + markFieldsWithLocalType(anonymousTypeDeclaration); + } +} +protected final void concatExpressionLists() { + expressionLengthStack[--expressionLengthPtr]++; +} +private final void concatNodeLists() { + /* + * This is a case where you have two sublists into the astStack that you want + * to merge in one list. There is no action required on the astStack. The only + * thing you need to do is merge the two lengths specified on the astStackLength. + * The top two length are for example: + * ... p n + * and you want to result in a list like: + * ... n+p + * This means that the p could be equals to 0 in case there is no astNode pushed + * on the astStack. + * Look at the InterfaceMemberDeclarations for an example. + */ + + astLengthStack[astLengthPtr - 1] += astLengthStack[astLengthPtr--]; +} +protected void consumeAllocationHeader() { + // ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt + + // ClassBodyopt produces a null item on the astStak if it produces NO class body + // An empty class body produces a 0 on the length stack..... + + if (currentElement == null){ + return; // should never occur, this consumeRule is only used in recovery mode + } + if (currentToken == TokenNameLBRACE){ + // beginning of an anonymous type + AnonymousLocalTypeDeclaration anonymousType = new AnonymousLocalTypeDeclaration(this.compilationUnit.compilationResult); + anonymousType.sourceStart = intStack[intPtr--]; + anonymousType.sourceEnd = rParenPos; // closing parenthesis + lastCheckPoint = anonymousType.bodyStart = scanner.currentPosition; + currentElement = currentElement.add(anonymousType, 0); + lastIgnoredToken = -1; + currentToken = 0; // opening brace already taken into account + return; + } + lastCheckPoint = scanner.startPosition; // force to restart at this exact position + restartRecovery = true; // request to restart from here on +} +protected void consumeArgumentList() { + // ArgumentList ::= ArgumentList ',' Expression + concatExpressionLists(); +} +protected void consumeArrayAccess(boolean unspecifiedReference) { + // ArrayAccess ::= Name '[' Expression ']' ==> true + // ArrayAccess ::= PrimaryNoNewArray '[' Expression ']' ==> false + + + //optimize push/pop + Expression exp; + if (unspecifiedReference) { + exp = + expressionStack[expressionPtr] = + new ArrayReference( + getUnspecifiedReferenceOptimized(), + expressionStack[expressionPtr]); + } else { + expressionPtr--; + expressionLengthPtr--; + exp = + expressionStack[expressionPtr] = + new ArrayReference( + expressionStack[expressionPtr], + expressionStack[expressionPtr + 1]); + } + exp.sourceEnd = endPosition; +} +protected void consumeArrayCreationExpression() { + // ArrayCreationExpression ::= 'new' PrimitiveType DimWithOrWithOutExprs ArrayInitializeropt + // ArrayCreationExpression ::= 'new' ClassOrInterfaceType DimWithOrWithOutExprs ArrayInitializeropt + + int length; + ArrayAllocationExpression aae = new ArrayAllocationExpression(); + if (expressionLengthStack[expressionLengthPtr] != 0) { + expressionLengthPtr -- ; + aae.initializer = (ArrayInitializer) expressionStack[expressionPtr--]; + } else { + expressionLengthPtr--; + } + + aae.type = getTypeReference(0); + length = (expressionLengthStack[expressionLengthPtr--]); + expressionPtr -= length ; + System.arraycopy( + expressionStack, + expressionPtr+1, + aae.dimensions = new Expression[length], + 0, + length); + aae.sourceStart = intStack[intPtr--]; + if (aae.initializer == null) { + aae.sourceEnd = endPosition; + } else { + aae.sourceEnd = aae.initializer.sourceEnd ; + } + pushOnExpressionStack(aae); +} +protected void consumeArrayInitializer() { + // ArrayInitializer ::= '{' VariableInitializers '}' + // ArrayInitializer ::= '{' VariableInitializers , '}' + + arrayInitializer(expressionLengthStack[expressionLengthPtr--]); +} + +protected void consumeAssertStatement() { + // AssertStatement ::= 'assert' Expression ':' Expression ';' + expressionLengthPtr-=2; + pushOnAstStack(new AssertStatement(expressionStack[expressionPtr--], expressionStack[expressionPtr--], intStack[intPtr--])); +} + +protected void consumeAssignment() { + // Assignment ::= LeftHandSide AssignmentOperator AssignmentExpression + //optimize the push/pop + + int op = intStack[intPtr--] ; //<--the encoded operator + + expressionPtr -- ; expressionLengthPtr -- ; + expressionStack[expressionPtr] = + (op != EQUAL ) ? + new CompoundAssignment( + expressionStack[expressionPtr] , + expressionStack[expressionPtr+1], + op, + scanner.startPosition - 1) : + new Assignment( + expressionStack[expressionPtr] , + expressionStack[expressionPtr+1], + scanner.startPosition - 1); +} +protected void consumeAssignmentOperator(int pos) { + // AssignmentOperator ::= '=' + // AssignmentOperator ::= '*=' + // AssignmentOperator ::= '/=' + // AssignmentOperator ::= '%=' + // AssignmentOperator ::= '+=' + // AssignmentOperator ::= '-=' + // AssignmentOperator ::= '<<=' + // AssignmentOperator ::= '>>=' + // AssignmentOperator ::= '>>>=' + // AssignmentOperator ::= '&=' + // AssignmentOperator ::= '^=' + // AssignmentOperator ::= '|=' + + try { + intStack[++intPtr] = pos; + } catch (IndexOutOfBoundsException e) { + //intPtr is correct + int oldStackLength = intStack.length; + int oldStack[] = intStack; + intStack = new int[oldStackLength + StackIncrement]; + System.arraycopy(oldStack, 0, intStack, 0, oldStackLength); + intStack[intPtr] = pos; + } +} +protected void consumeBinaryExpression(int op) { + // MultiplicativeExpression ::= MultiplicativeExpression '*' UnaryExpression + // MultiplicativeExpression ::= MultiplicativeExpression '/' UnaryExpression + // MultiplicativeExpression ::= MultiplicativeExpression '%' UnaryExpression + // AdditiveExpression ::= AdditiveExpression '+' MultiplicativeExpression + // AdditiveExpression ::= AdditiveExpression '-' MultiplicativeExpression + // ShiftExpression ::= ShiftExpression '<<' AdditiveExpression + // ShiftExpression ::= ShiftExpression '>>' AdditiveExpression + // ShiftExpression ::= ShiftExpression '>>>' AdditiveExpression + // RelationalExpression ::= RelationalExpression '<' ShiftExpression + // RelationalExpression ::= RelationalExpression '>' ShiftExpression + // RelationalExpression ::= RelationalExpression '<=' ShiftExpression + // RelationalExpression ::= RelationalExpression '>=' ShiftExpression + // AndExpression ::= AndExpression '&' EqualityExpression + // ExclusiveOrExpression ::= ExclusiveOrExpression '^' AndExpression + // InclusiveOrExpression ::= InclusiveOrExpression '|' ExclusiveOrExpression + // ConditionalAndExpression ::= ConditionalAndExpression '&&' InclusiveOrExpression + // ConditionalOrExpression ::= ConditionalOrExpression '||' ConditionalAndExpression + + //optimize the push/pop + + expressionPtr--; + expressionLengthPtr--; + if (op == OR_OR) { + expressionStack[expressionPtr] = + new OR_OR_Expression( + expressionStack[expressionPtr], + expressionStack[expressionPtr + 1], + op); + } else { + if (op == AND_AND) { + expressionStack[expressionPtr] = + new AND_AND_Expression( + expressionStack[expressionPtr], + expressionStack[expressionPtr + 1], + op); + } else { + // look for "string1" + "string2" + if ((op == PLUS) && optimizeStringLiterals) { + Expression expr1, expr2; + expr1 = expressionStack[expressionPtr]; + expr2 = expressionStack[expressionPtr + 1]; + if (expr1 instanceof StringLiteral) { + if (expr2 instanceof CharLiteral) { // string+char + expressionStack[expressionPtr] = + ((StringLiteral) expr1).extendWith((CharLiteral) expr2); + } else if (expr2 instanceof StringLiteral) { //string+string + expressionStack[expressionPtr] = + ((StringLiteral) expr1).extendWith((StringLiteral) expr2); + } else { + expressionStack[expressionPtr] = new BinaryExpression(expr1, expr2, PLUS); + } + } else { + expressionStack[expressionPtr] = new BinaryExpression(expr1, expr2, PLUS); + } + } else { + expressionStack[expressionPtr] = + new BinaryExpression( + expressionStack[expressionPtr], + expressionStack[expressionPtr + 1], + op); + } + } + } +} +protected void consumeBlock() { + // Block ::= OpenBlock '{' BlockStatementsopt '}' + // simpler action for empty blocks + + int length; + if ((length = astLengthStack[astLengthPtr--]) == 0) { // empty block + pushOnAstStack(Block.EmptyWith(intStack[intPtr--], endStatementPosition)); + realBlockPtr--; // still need to pop the block variable counter + } else { + Block bk = new Block(realBlockStack[realBlockPtr--]); + astPtr -= length; + System.arraycopy( + astStack, + astPtr + 1, + bk.statements = new Statement[length], + 0, + length); + pushOnAstStack(bk); + bk.sourceStart = intStack[intPtr--]; + bk.sourceEnd = endStatementPosition; + } +} +protected void consumeBlockStatements() { + // BlockStatements ::= BlockStatements BlockStatement + concatNodeLists(); +} +protected void consumeCaseLabel() { + // SwitchLabel ::= 'case' ConstantExpression ':' + expressionLengthPtr--; + pushOnAstStack(new Case(intStack[intPtr--], expressionStack[expressionPtr--])); +} +protected void consumeCastExpression() { + // CastExpression ::= PushLPAREN PrimitiveType Dimsopt PushRPAREN UnaryExpression + // CastExpression ::= PushLPAREN Name Dims PushRPAREN UnaryExpressionNotPlusMinus + + //intStack : posOfLeftParen dim posOfRightParen + + //optimize the push/pop + + Expression exp, cast, castType; + int end = intStack[intPtr--]; + expressionStack[expressionPtr] = cast = new CastExpression(exp = expressionStack[expressionPtr], castType = getTypeReference(intStack[intPtr--])); + castType.sourceEnd = end - 1; + castType.sourceStart = (cast.sourceStart = intStack[intPtr--]) + 1; + cast.sourceEnd = exp.sourceEnd; +} +protected void consumeCastExpressionLL1() { + //CastExpression ::= '(' Expression ')' UnaryExpressionNotPlusMinus + // Expression is used in order to make the grammar LL1 + + //optimize push/pop + + Expression castType,cast,exp; + expressionPtr--; + expressionStack[expressionPtr] = + cast = new CastExpression( exp=expressionStack[expressionPtr+1] , + castType = getTypeReference(expressionStack[expressionPtr])); + expressionLengthPtr -- ; + updateSourcePosition(castType); + cast.sourceStart=castType.sourceStart; + cast.sourceEnd=exp.sourceEnd; + castType.sourceStart++; + castType.sourceEnd--; + } +protected void consumeCatches() { + // Catches ::= Catches CatchClause + optimizedConcatNodeLists(); +} +protected void consumeCatchHeader() { + // CatchDeclaration ::= 'catch' '(' FormalParameter ')' '{' + + if (currentElement == null){ + return; // should never occur, this consumeRule is only used in recovery mode + } + // current element should be a block due to the presence of the opening brace + if (!(currentElement instanceof RecoveredBlock)){ + return; + } + // exception argument is already on astStack + ((RecoveredBlock)currentElement).attach( + new RecoveredLocalVariable((Argument)astStack[astPtr--], currentElement, 0)); // insert catch variable in catch block + lastCheckPoint = scanner.startPosition; // force to restart at this exact position + restartRecovery = true; // request to restart from here on + lastIgnoredToken = -1; +} +protected void consumeClassBodyDeclaration() { + // ClassBodyDeclaration ::= Diet Block + //push an Initializer + //optimize the push/pop + nestedMethod[nestedType]--; + Initializer initializer = new Initializer((Block) astStack[astPtr], 0); + intPtr--; // pop sourcestart left on the stack by consumeNestedMethod. + realBlockPtr--; // pop the block variable counter left on the stack by consumeNestedMethod + int javadocCommentStart = intStack[intPtr--]; + if (javadocCommentStart != -1) { + initializer.declarationSourceStart = javadocCommentStart; + } + astStack[astPtr] = initializer; + initializer.sourceEnd = endStatementPosition; + initializer.declarationSourceEnd = flushAnnotationsDefinedPriorTo(endStatementPosition); +} +protected void consumeClassBodyDeclarations() { + // ClassBodyDeclarations ::= ClassBodyDeclarations ClassBodyDeclaration + concatNodeLists(); +} +protected void consumeClassBodyDeclarationsopt() { + // ClassBodyDeclarationsopt ::= NestedType ClassBodyDeclarations + nestedType-- ; +} +protected void consumeClassBodyopt() { + // ClassBodyopt ::= $empty + pushOnAstStack(null); + endPosition = scanner.startPosition - 1; +} +protected void consumeClassDeclaration() { + // ClassDeclaration ::= ClassHeader ClassBody + + int length; + if ((length = astLengthStack[astLengthPtr--]) != 0) { + //there are length declarations + //dispatch according to the type of the declarations + dispatchDeclarationInto(length); + } + + TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr]; + + // mark fields and initializer with local type mark if needed + markFieldsWithLocalType(typeDecl); + + //convert constructor that do not have the type's name into methods + boolean hasConstructor = typeDecl.checkConstructors(this); + + //add the default constructor when needed (interface don't have it) + if (!hasConstructor) { + boolean insideFieldInitializer = false; + if (diet) { + for (int i = nestedType; i > 0; i--){ + if (variablesCounter[i] > 0) { + insideFieldInitializer = true; + break; + } + } + } + typeDecl.createsInternalConstructor(!diet || insideFieldInitializer, true); + } + + //always add (will be remove at code gen time if empty) + if (this.scanner.containsAssertKeyword) { + typeDecl.bits |= AstNode.AddAssertionMASK; + } + typeDecl.addClinit(); + typeDecl.bodyEnd = endStatementPosition; + typeDecl.declarationSourceEnd = flushAnnotationsDefinedPriorTo(endStatementPosition); +} +protected void consumeClassHeader() { + // ClassHeader ::= ClassHeaderName ClassHeaderExtendsopt ClassHeaderImplementsopt + + TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr]; + if (currentToken == TokenNameLBRACE) { + typeDecl.bodyStart = scanner.currentPosition; + } + if (currentElement != null) { + restartRecovery = true; // used to avoid branching back into the regular automaton + } + // flush the comments related to the class header + scanner.commentPtr = -1; +} +protected void consumeClassHeaderExtends() { + // ClassHeaderExtends ::= 'extends' ClassType + // There is a class declaration on the top of stack + TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr]; + //superclass + typeDecl.superclass = getTypeReference(0); + typeDecl.bodyStart = typeDecl.superclass.sourceEnd + 1; + // recovery + if (currentElement != null){ + lastCheckPoint = typeDecl.bodyStart; + } +} +protected void consumeClassHeaderImplements() { + // ClassHeaderImplements ::= 'implements' InterfaceTypeList + int length = astLengthStack[astLengthPtr--]; + //super interfaces + astPtr -= length; + // There is a class declaration on the top of stack + TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr]; + System.arraycopy( + astStack, + astPtr + 1, + typeDecl.superInterfaces = new TypeReference[length], + 0, + length); + typeDecl.bodyStart = typeDecl.superInterfaces[length-1].sourceEnd + 1; + listLength = 0; // reset after having read super-interfaces + // recovery + if (currentElement != null) { // is recovering + lastCheckPoint = typeDecl.bodyStart; + } +} +protected void consumeClassHeaderName() { + // ClassHeaderName ::= Modifiersopt 'class' 'Identifier' + TypeDeclaration typeDecl; + if (nestedMethod[nestedType] == 0) { + if (nestedType != 0) { + typeDecl = new MemberTypeDeclaration(this.compilationUnit.compilationResult); + } else { + typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult); + } + } else { + // Record that the block has a declaration for local types + typeDecl = new LocalTypeDeclaration(this.compilationUnit.compilationResult); + markCurrentMethodWithLocalType(); + blockReal(); + } + + //highlight the name of the type + long pos = identifierPositionStack[identifierPtr]; + typeDecl.sourceEnd = (int) pos; + typeDecl.sourceStart = (int) (pos >>> 32); + typeDecl.name = identifierStack[identifierPtr--]; + identifierLengthPtr--; + + //compute the declaration source too + // 'class' and 'interface' push two int positions: the beginning of the class token and its end. + // we want to keep the beginning position but get rid of the end position + // it is only used for the ClassLiteralAccess positions. + typeDecl.declarationSourceStart = intStack[intPtr--]; + intPtr--; // remove the end position of the class token + + typeDecl.modifiersSourceStart = intStack[intPtr--]; + typeDecl.modifiers = intStack[intPtr--]; + if (typeDecl.modifiersSourceStart >= 0) { + typeDecl.declarationSourceStart = typeDecl.modifiersSourceStart; + } + typeDecl.bodyStart = typeDecl.sourceEnd + 1; + pushOnAstStack(typeDecl); + + listLength = 0; // will be updated when reading super-interfaces + // recovery + if (currentElement != null){ + lastCheckPoint = typeDecl.bodyStart; + currentElement = currentElement.add(typeDecl, 0); + lastIgnoredToken = -1; + } +} +protected void consumeClassInstanceCreationExpression() { + // ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt + classInstanceCreation(false); +} +protected void consumeClassInstanceCreationExpressionName() { + // ClassInstanceCreationExpressionName ::= Name '.' + pushOnExpressionStack(getUnspecifiedReferenceOptimized()); +} +protected void consumeClassInstanceCreationExpressionQualified() { + // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt + // ClassInstanceCreationExpression ::= ClassInstanceCreationExpressionName 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt + + classInstanceCreation(true); // <-- push the Qualifed.... + + expressionLengthPtr--; + QualifiedAllocationExpression qae = + (QualifiedAllocationExpression) expressionStack[expressionPtr--]; + qae.enclosingInstance = expressionStack[expressionPtr]; + expressionStack[expressionPtr] = qae; + qae.sourceStart = qae.enclosingInstance.sourceStart; +} +protected void consumeClassTypeElt() { + // ClassTypeElt ::= ClassType + pushOnAstStack(getTypeReference(0)); + /* if incomplete thrown exception list, listLength counter will not have been reset, + indicating that some items are available on the stack */ + listLength++; +} +protected void consumeClassTypeList() { + // ClassTypeList ::= ClassTypeList ',' ClassTypeElt + optimizedConcatNodeLists(); +} +protected void consumeCompilationUnit() { + // CompilationUnit ::= EnterCompilationUnit PackageDeclarationopt ImportDeclarationsopt + // do nothing by default +} +protected void consumeConditionalExpression(int op) { + // ConditionalExpression ::= ConditionalOrExpression '?' Expression ':' ConditionalExpression + //optimize the push/pop + + expressionPtr -= 2; + expressionLengthPtr -= 2; + expressionStack[expressionPtr] = + new ConditionalExpression( + expressionStack[expressionPtr], + expressionStack[expressionPtr + 1], + expressionStack[expressionPtr + 2]); +} +protected void consumeConstructorBlockStatements() { + // ConstructorBody ::= NestedMethod '{' ExplicitConstructorInvocation BlockStatements '}' + concatNodeLists(); // explictly add the first statement into the list of statements +} +protected void consumeConstructorBody() { + // ConstructorBody ::= NestedMethod '{' BlockStatementsopt '}' + // ConstructorBody ::= NestedMethod '{' ExplicitConstructorInvocation '}' + nestedMethod[nestedType] --; +} +protected void consumeConstructorDeclaration() { + // ConstructorDeclaration ::= ConstructorHeader ConstructorBody + + /* + astStack : MethodDeclaration statements + identifierStack : name + ==> + astStack : MethodDeclaration + identifierStack : + */ + + //must provide a default constructor call when needed + + int length; + + // pop the position of the { (body of the method) pushed in block decl + intPtr--; + + //statements + realBlockPtr--; + ExplicitConstructorCall constructorCall = null; + Statement[] statements = null; + if ((length = astLengthStack[astLengthPtr--]) != 0) { + astPtr -= length; + if (astStack[astPtr + 1] instanceof ExplicitConstructorCall) { + //avoid a isSomeThing that would only be used here BUT what is faster between two alternatives ? + System.arraycopy( + astStack, + astPtr + 2, + statements = new Statement[length - 1], + 0, + length - 1); + constructorCall = (ExplicitConstructorCall) astStack[astPtr + 1]; + } else { //need to add explicitly the super(); + System.arraycopy( + astStack, + astPtr + 1, + statements = new Statement[length], + 0, + length); + constructorCall = SuperReference.implicitSuperConstructorCall(); + } + } else { + if (!diet){ + // add it only in non-diet mode, if diet_bodies, then constructor call will be added elsewhere. + constructorCall = SuperReference.implicitSuperConstructorCall(); + } + } + + // now we know that the top of stack is a constructorDeclaration + ConstructorDeclaration cd = (ConstructorDeclaration) astStack[astPtr]; + cd.constructorCall = constructorCall; + cd.statements = statements; + + //highlight of the implicit call on the method name + if (constructorCall != null && cd.constructorCall.sourceEnd == 0) { + cd.constructorCall.sourceEnd = cd.sourceEnd; + cd.constructorCall.sourceStart = cd.sourceStart; + } + + //watch for } that could be given as a unicode ! ( u007D is '}' ) + // store the endPosition (position just before the '}') in case there is + // a trailing comment behind the end of the method + cd.bodyEnd = endPosition; + cd.declarationSourceEnd = flushAnnotationsDefinedPriorTo(endStatementPosition); +} + +protected void consumeInvalidConstructorDeclaration() { + // ConstructorDeclaration ::= ConstructorHeader ';' + // now we know that the top of stack is a constructorDeclaration + ConstructorDeclaration cd = (ConstructorDeclaration) astStack[astPtr]; + + cd.bodyEnd = endPosition; // position just before the trailing semi-colon + cd.declarationSourceEnd = flushAnnotationsDefinedPriorTo(endStatementPosition); + // report the problem and continue the parsing - narrowing the problem onto the method +} +protected void consumeConstructorHeader() { + // ConstructorHeader ::= ConstructorHeaderName MethodHeaderParameters MethodHeaderThrowsClauseopt + + AbstractMethodDeclaration method = (AbstractMethodDeclaration)astStack[astPtr]; + + if (currentToken == TokenNameLBRACE){ + method.bodyStart = scanner.currentPosition; + } + // recovery + if (currentElement != null){ + restartRecovery = true; // used to avoid branching back into the regular automaton + } +} +protected void consumeConstructorHeaderName() { + + /* recovering - might be an empty message send */ + if (currentElement != null){ + if (lastIgnoredToken == TokenNamenew){ // was an allocation expression + lastCheckPoint = scanner.startPosition; // force to restart at this exact position + restartRecovery = true; + return; + } + } + + // ConstructorHeaderName ::= Modifiersopt 'Identifier' '(' + ConstructorDeclaration cd = new ConstructorDeclaration(this.compilationUnit.compilationResult); + + //name -- this is not really revelant but we do ..... + cd.selector = identifierStack[identifierPtr]; + long selectorSource = identifierPositionStack[identifierPtr--]; + identifierLengthPtr--; + + //modifiers + cd.declarationSourceStart = intStack[intPtr--]; + cd.modifiers = intStack[intPtr--]; + + //highlight starts at the selector starts + cd.sourceStart = (int) (selectorSource >>> 32); + pushOnAstStack(cd); + cd.sourceEnd = lParenPos; + cd.bodyStart = lParenPos+1; + listLength = 0; // initialize listLength before reading parameters/throws + + // recovery + if (currentElement != null){ + lastCheckPoint = cd.bodyStart; + if ((currentElement instanceof RecoveredType && lastIgnoredToken != TokenNameDOT) + || cd.modifiers != 0){ + currentElement = currentElement.add(cd, 0); + lastIgnoredToken = -1; + } + } +} +protected void consumeDefaultLabel() { + // SwitchLabel ::= 'default' ':' + pushOnAstStack(new DefaultCase(intStack[intPtr--], intStack[intPtr--])); +} +protected void consumeDefaultModifiers() { + checkAnnotation(); // might update modifiers with AccDeprecated + pushOnIntStack(modifiers); // modifiers + pushOnIntStack( + modifiersSourceStart >= 0 ? modifiersSourceStart : scanner.startPosition); + resetModifiers(); +} +protected void consumeDiet() { + // Diet ::= $empty + checkAnnotation(); + pushOnIntStack(modifiersSourceStart); // push the start position of a javadoc comment if there is one + jumpOverMethodBody(); +} +protected void consumeDims() { + // Dims ::= DimsLoop + pushOnIntStack(dimensions); + dimensions = 0; +} +protected void consumeDimWithOrWithOutExpr() { + // DimWithOrWithOutExpr ::= '[' ']' + pushOnExpressionStack(null); +} +protected void consumeDimWithOrWithOutExprs() { + // DimWithOrWithOutExprs ::= DimWithOrWithOutExprs DimWithOrWithOutExpr + concatExpressionLists(); +} +protected void consumeEmptyArgumentListopt() { + // ArgumentListopt ::= $empty + pushOnExpressionStackLengthStack(0); +} +protected void consumeEmptyArrayInitializer() { + // ArrayInitializer ::= '{' ,opt '}' + arrayInitializer(0); +} +protected void consumeEmptyArrayInitializeropt() { + // ArrayInitializeropt ::= $empty + pushOnExpressionStackLengthStack(0); +} +protected void consumeEmptyBlockStatementsopt() { + // BlockStatementsopt ::= $empty + pushOnAstLengthStack(0); +} +protected void consumeEmptyCatchesopt() { + // Catchesopt ::= $empty + pushOnAstLengthStack(0); +} +protected void consumeEmptyClassBodyDeclarationsopt() { + // ClassBodyDeclarationsopt ::= $empty + pushOnAstLengthStack(0); +} +protected void consumeEmptyClassMemberDeclaration() { + // ClassMemberDeclaration ::= ';' + pushOnAstLengthStack(0); +} +protected void consumeEmptyDimsopt() { + // Dimsopt ::= $empty + pushOnIntStack(0); +} +protected void consumeEmptyExpression() { + // Expressionopt ::= $empty + pushOnExpressionStackLengthStack(0); +} +protected void consumeEmptyForInitopt() { + // ForInitopt ::= $empty + pushOnAstLengthStack(0); +} +protected void consumeEmptyForUpdateopt() { + // ForUpdateopt ::= $empty + pushOnExpressionStackLengthStack(0); +} +protected void consumeEmptyImportDeclarationsopt() { + // ImportDeclarationsopt ::= $empty + pushOnAstLengthStack(0); +} +protected void consumeEmptyInterfaceMemberDeclaration() { + // InterfaceMemberDeclaration ::= ';' + pushOnAstLengthStack(0); +} +protected void consumeEmptyInterfaceMemberDeclarationsopt() { + // InterfaceMemberDeclarationsopt ::= $empty + pushOnAstLengthStack(0); +} +protected void consumeEmptyStatement() { + // EmptyStatement ::= ';' + if (this.scanner.source[endStatementPosition] == ';') { + pushOnAstStack(new EmptyStatement(endStatementPosition, endStatementPosition)); + } else { + // we have a Unicode for the ';' (/u003B) + pushOnAstStack(new EmptyStatement(endStatementPosition - 5, endStatementPosition)); + } +} +protected void consumeEmptySwitchBlock() { + // SwitchBlock ::= '{' '}' + pushOnAstLengthStack(0); +} +protected void consumeEmptyTypeDeclaration() { + // TypeDeclaration ::= ';' + pushOnAstLengthStack(0); +} +protected void consumeEmptyTypeDeclarationsopt() { + // TypeDeclarationsopt ::= $empty + pushOnAstLengthStack(0); +} +protected void consumeEnterAnonymousClassBody() { + // EnterAnonymousClassBody ::= $empty + QualifiedAllocationExpression alloc; + AnonymousLocalTypeDeclaration anonymousType = + new AnonymousLocalTypeDeclaration(this.compilationUnit.compilationResult); + alloc = + anonymousType.allocation = new QualifiedAllocationExpression(anonymousType); + markCurrentMethodWithLocalType(); + pushOnAstStack(anonymousType); + + alloc.sourceEnd = rParenPos; //the position has been stored explicitly + int argumentLength; + if ((argumentLength = expressionLengthStack[expressionLengthPtr--]) != 0) { + expressionPtr -= argumentLength; + System.arraycopy( + expressionStack, + expressionPtr + 1, + alloc.arguments = new Expression[argumentLength], + 0, + argumentLength); + } + alloc.type = getTypeReference(0); + + anonymousType.sourceEnd = alloc.sourceEnd; + //position at the type while it impacts the anonymous declaration + anonymousType.sourceStart = anonymousType.declarationSourceStart = alloc.type.sourceStart; + alloc.sourceStart = intStack[intPtr--]; + pushOnExpressionStack(alloc); + + anonymousType.bodyStart = scanner.currentPosition; + listLength = 0; // will be updated when reading super-interfaces + // recovery + if (currentElement != null){ + lastCheckPoint = anonymousType.bodyStart; + // the recoveryTokenCheck will deal with the open brace + currentElement = currentElement.add(anonymousType, 0); + currentToken = 0; // opening brace already taken into account + lastIgnoredToken = -1; + } +} +protected void consumeEnterCompilationUnit() { + // EnterCompilationUnit ::= $empty + // do nothing by default +} +protected void consumeEnterVariable() { + // EnterVariable ::= $empty + // do nothing by default + + char[] name = identifierStack[identifierPtr]; + long namePosition = identifierPositionStack[identifierPtr]; + int extendedDimension = intStack[intPtr--]; + AbstractVariableDeclaration declaration; + // create the ast node + boolean isLocalDeclaration = nestedMethod[nestedType] != 0; + if (isLocalDeclaration) { + // create the local variable declarations + declaration = + this.createLocalDeclaration(null, name, (int) (namePosition >>> 32), (int) namePosition); + } else { + // create the field declaration + declaration = + this.createFieldDeclaration(null, name, (int) (namePosition >>> 32), (int) namePosition); + } + + identifierPtr--; + identifierLengthPtr--; + TypeReference type; + int variableIndex = variablesCounter[nestedType]; + int typeDim = 0; + if (variableIndex == 0) { + // first variable of the declaration (FieldDeclaration or LocalDeclaration) + if (isLocalDeclaration) { + declaration.declarationSourceStart = intStack[intPtr--]; + declaration.modifiers = intStack[intPtr--]; + type = getTypeReference(typeDim = intStack[intPtr--]); // type dimension + if (declaration.declarationSourceStart == -1) { + // this is true if there is no modifiers for the local variable declaration + declaration.declarationSourceStart = type.sourceStart; + } + pushOnAstStack(type); + } else { + type = getTypeReference(typeDim = intStack[intPtr--]); // type dimension + pushOnAstStack(type); + declaration.declarationSourceStart = intStack[intPtr--]; + declaration.modifiers = intStack[intPtr--]; + } + } else { + type = (TypeReference) astStack[astPtr - variableIndex]; + typeDim = type.dimensions(); + AbstractVariableDeclaration previousVariable = + (AbstractVariableDeclaration) astStack[astPtr]; + declaration.declarationSourceStart = previousVariable.declarationSourceStart; + declaration.modifiers = previousVariable.modifiers; + } + + if (extendedDimension == 0) { + declaration.type = type; + } else { + int dimension = typeDim + extendedDimension; + //on the identifierLengthStack there is the information about the type.... + int baseType; + if ((baseType = identifierLengthStack[identifierLengthPtr + 1]) < 0) { + //it was a baseType + int typeSourceStart = type.sourceStart; + int typeSourceEnd = type.sourceEnd; + type = TypeReference.baseTypeReference(-baseType, dimension); + type.sourceStart = typeSourceStart; + type.sourceEnd = typeSourceEnd; + declaration.type = type; + } else { + declaration.type = this.copyDims(type, dimension); + } + } + variablesCounter[nestedType]++; + pushOnAstStack(declaration); + // recovery + if (currentElement != null) { + if (!(currentElement instanceof RecoveredType) + && (currentToken == TokenNameDOT + //|| declaration.modifiers != 0 + || (scanner.getLineNumber(declaration.type.sourceStart) + != scanner.getLineNumber((int) (namePosition >>> 32))))){ + lastCheckPoint = (int) (namePosition >>> 32); + restartRecovery = true; + return; + } + if (isLocalDeclaration){ + LocalDeclaration localDecl = (LocalDeclaration) astStack[astPtr]; + lastCheckPoint = localDecl.sourceEnd + 1; + currentElement = currentElement.add(localDecl, 0); + } else { + FieldDeclaration fieldDecl = (FieldDeclaration) astStack[astPtr]; + lastCheckPoint = fieldDecl.sourceEnd + 1; + currentElement = currentElement.add(fieldDecl, 0); + } + lastIgnoredToken = -1; + } +} +protected void consumeEqualityExpression(int op) { + // EqualityExpression ::= EqualityExpression '==' RelationalExpression + // EqualityExpression ::= EqualityExpression '!=' RelationalExpression + + //optimize the push/pop + + expressionPtr--; + expressionLengthPtr--; + expressionStack[expressionPtr] = + new EqualExpression( + expressionStack[expressionPtr], + expressionStack[expressionPtr + 1], + op); +} +protected void consumeExitVariableWithInitialization() { + // ExitVariableWithInitialization ::= $empty + // do nothing by default + expressionLengthPtr--; + AbstractVariableDeclaration variableDecl = (AbstractVariableDeclaration) astStack[astPtr]; + variableDecl.initialization = expressionStack[expressionPtr--]; + // we need to update the declarationSourceEnd of the local variable declaration to the + // source end position of the initialization expression + variableDecl.declarationSourceEnd = variableDecl.initialization.sourceEnd; + variableDecl.declarationEnd = variableDecl.initialization.sourceEnd; +} +protected void consumeExitVariableWithoutInitialization() { + // ExitVariableWithoutInitialization ::= $empty + // do nothing by default +} +protected void consumeExplicitConstructorInvocation(int flag, int recFlag) { + + /* flag allows to distinguish 3 cases : + (0) : + ExplicitConstructorInvocation ::= 'this' '(' ArgumentListopt ')' ';' + ExplicitConstructorInvocation ::= 'super' '(' ArgumentListopt ')' ';' + (1) : + ExplicitConstructorInvocation ::= Primary '.' 'super' '(' ArgumentListopt ')' ';' + ExplicitConstructorInvocation ::= Primary '.' 'this' '(' ArgumentListopt ')' ';' + (2) : + ExplicitConstructorInvocation ::= Name '.' 'super' '(' ArgumentListopt ')' ';' + ExplicitConstructorInvocation ::= Name '.' 'this' '(' ArgumentListopt ')' ';' + */ + int startPosition = intStack[intPtr--]; + ExplicitConstructorCall ecc = new ExplicitConstructorCall(recFlag); + int length; + if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) { + expressionPtr -= length; + System.arraycopy(expressionStack, expressionPtr + 1, ecc.arguments = new Expression[length], 0, length); + } + switch (flag) { + case 0 : + ecc.sourceStart = startPosition; + break; + case 1 : + expressionLengthPtr--; + ecc.sourceStart = (ecc.qualification = expressionStack[expressionPtr--]).sourceStart; + break; + case 2 : + ecc.sourceStart = (ecc.qualification = getUnspecifiedReferenceOptimized()).sourceStart; + break; + }; + pushOnAstStack(ecc); + ecc.sourceEnd = endPosition; +} +protected void consumeExpressionStatement() { + // ExpressionStatement ::= StatementExpression ';' + expressionLengthPtr--; + pushOnAstStack(expressionStack[expressionPtr--]); +} +protected void consumeFieldAccess(boolean isSuperAccess) { + // FieldAccess ::= Primary '.' 'Identifier' + // FieldAccess ::= 'super' '.' 'Identifier' + + FieldReference fr = + new FieldReference( + identifierStack[identifierPtr], + identifierPositionStack[identifierPtr--]); + identifierLengthPtr--; + if (isSuperAccess) { + //considerates the fieldReference beginning at the 'super' .... + fr.sourceStart = intStack[intPtr--]; + fr.receiver = new SuperReference(fr.sourceStart, endPosition); + pushOnExpressionStack(fr); + } else { + //optimize push/pop + if ((fr.receiver = expressionStack[expressionPtr]).isThis()) { + //fieldreference begins at the this + fr.sourceStart = fr.receiver.sourceStart; + } + expressionStack[expressionPtr] = fr; + } +} +protected void consumeFieldDeclaration() { + // See consumeLocalVariableDeclarationDefaultModifier() in case of change: duplicated code + // FieldDeclaration ::= Modifiersopt Type VariableDeclarators ';' + + /* + astStack : + expressionStack: Expression Expression ...... Expression + identifierStack : type identifier identifier ...... identifier + intStack : typeDim dim dim dim + ==> + astStack : FieldDeclaration FieldDeclaration ...... FieldDeclaration + expressionStack : + identifierStack : + intStack : + + */ + int variableDeclaratorsCounter = astLengthStack[astLengthPtr]; + + for (int i = variableDeclaratorsCounter - 1; i >= 0; i--) { + FieldDeclaration fieldDeclaration = (FieldDeclaration) astStack[astPtr - i]; + fieldDeclaration.declarationSourceEnd = endStatementPosition; + fieldDeclaration.declarationEnd = endStatementPosition; // semi-colon included + } + updateSourceDeclarationParts(variableDeclaratorsCounter); + int endPos = flushAnnotationsDefinedPriorTo(endStatementPosition); + if (endPos != endStatementPosition) { + for (int i = 0; i < variableDeclaratorsCounter; i++) { + FieldDeclaration fieldDeclaration = (FieldDeclaration) astStack[astPtr - i]; + fieldDeclaration.declarationSourceEnd = endPos; + } + } + // update the astStack, astPtr and astLengthStack + int startIndex = astPtr - variablesCounter[nestedType] + 1; + System.arraycopy( + astStack, + startIndex, + astStack, + startIndex - 1, + variableDeclaratorsCounter); + astPtr--; // remove the type reference + astLengthStack[--astLengthPtr] = variableDeclaratorsCounter; + + // recovery + if (currentElement != null) { + lastCheckPoint = endPos + 1; + if (currentElement.parent != null && currentElement instanceof RecoveredField){ + currentElement = currentElement.parent; + } + restartRecovery = true; + } + variablesCounter[nestedType] = 0; +} +protected void consumeForceNoDiet() { + // ForceNoDiet ::= $empty + dietInt++; +} +protected void consumeForInit() { + // ForInit ::= StatementExpressionList + pushOnAstLengthStack(-1); +} +protected void consumeFormalParameter() { + // FormalParameter ::= Type VariableDeclaratorId ==> false + // FormalParameter ::= Modifiers Type VariableDeclaratorId ==> true + /* + astStack : + identifierStack : type identifier + intStack : dim dim + ==> + astStack : Argument + identifierStack : + intStack : + */ + + identifierLengthPtr--; + char[] name = identifierStack[identifierPtr]; + long namePositions = identifierPositionStack[identifierPtr--]; + TypeReference type = getTypeReference(intStack[intPtr--] + intStack[intPtr--]); + int modifierPositions = intStack[intPtr--]; + intPtr--; + Argument arg = + new Argument( + name, + namePositions, + type, + intStack[intPtr + 1] & ~AccDeprecated); // modifiers + arg.declarationSourceStart = modifierPositions; + pushOnAstStack(arg); + + /* if incomplete method header, listLength counter will not have been reset, + indicating that some arguments are available on the stack */ + listLength++; +} +protected void consumeFormalParameterList() { + // FormalParameterList ::= FormalParameterList ',' FormalParameter + optimizedConcatNodeLists(); +} +protected void consumeFormalParameterListopt() { + // FormalParameterListopt ::= $empty + pushOnAstLengthStack(0); +} +protected void consumeImportDeclarations() { + // ImportDeclarations ::= ImportDeclarations ImportDeclaration + optimizedConcatNodeLists(); +} +protected void consumeImportDeclarationsopt() { + // ImportDeclarationsopt ::= ImportDeclarations + int length; + if ((length = astLengthStack[astLengthPtr--]) != 0) { + astPtr -= length; + System.arraycopy( + astStack, + astPtr + 1, + compilationUnit.imports = new ImportReference[length], + 0, + length); + } +} +protected void consumeInstanceOfExpression(int op) { + // RelationalExpression ::= RelationalExpression 'instanceof' ReferenceType + //optimize the push/pop + + //by construction, no base type may be used in getTypeReference + Expression exp; + expressionStack[expressionPtr] = exp = + new InstanceOfExpression( + expressionStack[expressionPtr], + getTypeReference(intStack[intPtr--]), + op); + if (exp.sourceEnd == 0) { + //array on base type.... + exp.sourceEnd = scanner.startPosition - 1; + } + //the scanner is on the next token already.... +} +protected void consumeInterfaceDeclaration() { + // see consumeClassDeclaration in case of changes: duplicated code + // InterfaceDeclaration ::= InterfaceHeader InterfaceBody + int length; + if ((length = astLengthStack[astLengthPtr--]) != 0) { + //there are length declarations + //dispatch.....according to the type of the declarations + dispatchDeclarationInto(length); + } + + TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr]; + + // mark fields and initializer with local type mark if needed + markFieldsWithLocalType(typeDecl); + + //convert constructor that do not have the type's name into methods + typeDecl.checkConstructors(this); + + //always add (will be remove at code gen time if empty) + if (this.scanner.containsAssertKeyword) { + typeDecl.bits |= AstNode.AddAssertionMASK; + } + typeDecl.addClinit(); + typeDecl.bodyEnd = endStatementPosition; + typeDecl.declarationSourceEnd = flushAnnotationsDefinedPriorTo(endStatementPosition); +} +protected void consumeInterfaceHeader() { + // InterfaceHeader ::= InterfaceHeaderName InterfaceHeaderExtendsopt + + TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr]; + if (currentToken == TokenNameLBRACE){ + typeDecl.bodyStart = scanner.currentPosition; + } + if (currentElement != null){ + restartRecovery = true; // used to avoid branching back into the regular automaton + } + // flush the comments related to the interface header + scanner.commentPtr = -1; +} +protected void consumeInterfaceHeaderExtends() { + // InterfaceHeaderExtends ::= 'extends' InterfaceTypeList + int length = astLengthStack[astLengthPtr--]; + //super interfaces + astPtr -= length; + TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr]; + System.arraycopy( + astStack, + astPtr + 1, + typeDecl.superInterfaces = new TypeReference[length], + 0, + length); + typeDecl.bodyStart = typeDecl.superInterfaces[length-1].sourceEnd + 1; + listLength = 0; // reset after having read super-interfaces + // recovery + if (currentElement != null) { + lastCheckPoint = typeDecl.bodyStart; + } +} +protected void consumeInterfaceHeaderName() { + // InterfaceHeaderName ::= Modifiersopt 'interface' 'Identifier' + TypeDeclaration typeDecl; + if (nestedMethod[nestedType] == 0) { + if (nestedType != 0) { + typeDecl = new MemberTypeDeclaration(this.compilationUnit.compilationResult); + } else { + typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult); + } + } else { + // Record that the block has a declaration for local types + typeDecl = new LocalTypeDeclaration(this.compilationUnit.compilationResult); + markCurrentMethodWithLocalType(); + blockReal(); + } + + //highlight the name of the type + long pos = identifierPositionStack[identifierPtr]; + typeDecl.sourceEnd = (int) pos; + typeDecl.sourceStart = (int) (pos >>> 32); + typeDecl.name = identifierStack[identifierPtr--]; + identifierLengthPtr--; + + //compute the declaration source too + // 'class' and 'interface' push two int positions: the beginning of the class token and its end. + // we want to keep the beginning position but get rid of the end position + // it is only used for the ClassLiteralAccess positions. + typeDecl.declarationSourceStart = intStack[intPtr--]; + intPtr--; // remove the end position of the class token + typeDecl.modifiersSourceStart = intStack[intPtr--]; + typeDecl.modifiers = intStack[intPtr--]; + if (typeDecl.modifiersSourceStart >= 0) { + typeDecl.declarationSourceStart = typeDecl.modifiersSourceStart; + } + typeDecl.bodyStart = typeDecl.sourceEnd + 1; + pushOnAstStack(typeDecl); + listLength = 0; // will be updated when reading super-interfaces + // recovery + if (currentElement != null){ // is recovering + lastCheckPoint = typeDecl.bodyStart; + currentElement = currentElement.add(typeDecl, 0); + lastIgnoredToken = -1; + } +} +protected void consumeInterfaceMemberDeclarations() { + // InterfaceMemberDeclarations ::= InterfaceMemberDeclarations InterfaceMemberDeclaration + concatNodeLists(); +} +protected void consumeInterfaceMemberDeclarationsopt() { + // InterfaceMemberDeclarationsopt ::= NestedType InterfaceMemberDeclarations + nestedType--; +} +protected void consumeInterfaceType() { + // InterfaceType ::= ClassOrInterfaceType + pushOnAstStack(getTypeReference(0)); + /* if incomplete type header, listLength counter will not have been reset, + indicating that some interfaces are available on the stack */ + listLength++; +} +protected void consumeInterfaceTypeList() { + // InterfaceTypeList ::= InterfaceTypeList ',' InterfaceType + optimizedConcatNodeLists(); +} +protected void consumeLeftHandSide() { + // LeftHandSide ::= Name + + pushOnExpressionStack(getUnspecifiedReferenceOptimized()); +} +protected void consumeLeftParen() { + // PushLPAREN ::= '(' + pushOnIntStack(lParenPos); +} +protected void consumeLocalVariableDeclaration() { + // LocalVariableDeclaration ::= Modifiers Type VariableDeclarators ';' + + /* + astStack : + expressionStack: Expression Expression ...... Expression + identifierStack : type identifier identifier ...... identifier + intStack : typeDim dim dim dim + ==> + astStack : FieldDeclaration FieldDeclaration ...... FieldDeclaration + expressionStack : + identifierStack : + intStack : + + */ + int variableDeclaratorsCounter = astLengthStack[astLengthPtr]; + + // update the astStack, astPtr and astLengthStack + int startIndex = astPtr - variablesCounter[nestedType] + 1; + System.arraycopy( + astStack, + startIndex, + astStack, + startIndex - 1, + variableDeclaratorsCounter); + astPtr--; // remove the type reference + astLengthStack[--astLengthPtr] = variableDeclaratorsCounter; + variablesCounter[nestedType] = 0; +} +protected void consumeLocalVariableDeclarationStatement() { + // LocalVariableDeclarationStatement ::= LocalVariableDeclaration ';' + // see blockReal in case of change: duplicated code + // increment the amount of declared variables for this block + realBlockStack[realBlockPtr]++; +} +protected void consumeMethodBody() { + // MethodBody ::= NestedMethod '{' BlockStatementsopt '}' + nestedMethod[nestedType] --; +} +protected void consumeMethodDeclaration(boolean isNotAbstract) { + // MethodDeclaration ::= MethodHeader MethodBody + // AbstractMethodDeclaration ::= MethodHeader ';' + + /* + astStack : modifiers arguments throws statements + identifierStack : type name + intStack : dim dim dim + ==> + astStack : MethodDeclaration + identifierStack : + intStack : + */ + + int length; + if (isNotAbstract) { + // pop the position of the { (body of the method) pushed in block decl + intPtr--; + } + + int explicitDeclarations = 0; + Statement[] statements = null; + if (isNotAbstract) { + //statements + explicitDeclarations = realBlockStack[realBlockPtr--]; + if ((length = astLengthStack[astLengthPtr--]) != 0) + System.arraycopy( + astStack, + (astPtr -= length) + 1, + statements = new Statement[length], + 0, + length); + } + + // now we know that we have a method declaration at the top of the ast stack + MethodDeclaration md = (MethodDeclaration) astStack[astPtr]; + md.statements = statements; + md.explicitDeclarations = explicitDeclarations; + + // cannot be done in consumeMethodHeader because we have no idea whether or not there + // is a body when we reduce the method header + if (!isNotAbstract) { //remember the fact that the method has a semicolon body + md.modifiers |= AccSemicolonBody; + } + // store the endPosition (position just before the '}') in case there is + // a trailing comment behind the end of the method + md.bodyEnd = endPosition; + md.declarationSourceEnd = flushAnnotationsDefinedPriorTo(endStatementPosition); +} +protected void consumeMethodHeader() { + // MethodHeader ::= MethodHeaderName MethodHeaderParameters MethodHeaderExtendedDims ThrowsClauseopt + // retrieve end position of method declarator + AbstractMethodDeclaration method = (AbstractMethodDeclaration)astStack[astPtr]; + + if (currentToken == TokenNameLBRACE){ + method.bodyStart = scanner.currentPosition; + } + // recovery + if (currentElement != null){ + if (currentToken == TokenNameSEMICOLON){ + method.modifiers |= AccSemicolonBody; + method.declarationSourceEnd = scanner.currentPosition-1; + method.bodyEnd = scanner.currentPosition-1; + if (currentElement.parent != null){ + currentElement = currentElement.parent; + } + } + restartRecovery = true; // used to avoid branching back into the regular automaton + } +} +protected void consumeMethodHeaderExtendedDims() { + // MethodHeaderExtendedDims ::= Dimsopt + // now we update the returnType of the method + MethodDeclaration md = (MethodDeclaration) astStack[astPtr]; + int extendedDims = intStack[intPtr--]; + if (extendedDims != 0) { + TypeReference returnType = md.returnType; + md.sourceEnd = endPosition; + int dims = returnType.dimensions() + extendedDims; + int baseType; + if ((baseType = identifierLengthStack[identifierLengthPtr + 1]) < 0) { + //it was a baseType + int sourceStart = returnType.sourceStart; + int sourceEnd = returnType.sourceEnd; + returnType = TypeReference.baseTypeReference(-baseType, dims); + returnType.sourceStart = sourceStart; + returnType.sourceEnd = sourceEnd; + md.returnType = returnType; + } else { + md.returnType = this.copyDims(md.returnType, dims); + } + if (currentToken == TokenNameLBRACE){ + md.bodyStart = endPosition + 1; + } + // recovery + if (currentElement != null){ + lastCheckPoint = md.bodyStart; + } + } +} +protected void consumeMethodHeaderName() { + // MethodHeaderName ::= Modifiersopt Type 'Identifier' '(' + MethodDeclaration md = new MethodDeclaration(this.compilationUnit.compilationResult); + + //name + md.selector = identifierStack[identifierPtr]; + long selectorSource = identifierPositionStack[identifierPtr--]; + identifierLengthPtr--; + //type + md.returnType = getTypeReference(intStack[intPtr--]); + //modifiers + md.declarationSourceStart = intStack[intPtr--]; + md.modifiers = intStack[intPtr--]; + + //highlight starts at selector start + md.sourceStart = (int) (selectorSource >>> 32); + pushOnAstStack(md); + md.sourceEnd = lParenPos; + md.bodyStart = lParenPos+1; + listLength = 0; // initialize listLength before reading parameters/throws + + // recovery + if (currentElement != null){ + if (currentElement instanceof RecoveredType + //|| md.modifiers != 0 + || (scanner.getLineNumber(md.returnType.sourceStart) + == scanner.getLineNumber(md.sourceStart))){ + lastCheckPoint = md.bodyStart; + currentElement = currentElement.add(md, 0); + lastIgnoredToken = -1; + } else { + lastCheckPoint = md.sourceStart; + restartRecovery = true; + } + } +} +protected void consumeMethodHeaderParameters() { + // MethodHeaderParameters ::= FormalParameterListopt ')' + int length = astLengthStack[astLengthPtr--]; + astPtr -= length; + AbstractMethodDeclaration md = (AbstractMethodDeclaration) astStack[astPtr]; + md.sourceEnd = rParenPos; + //arguments + if (length != 0) { + System.arraycopy( + astStack, + astPtr + 1, + md.arguments = new Argument[length], + 0, + length); + } + md.bodyStart = rParenPos+1; + listLength = 0; // reset listLength after having read all parameters + // recovery + if (currentElement != null){ + lastCheckPoint = md.bodyStart; + if (currentElement.parseTree() == md) return; + + // might not have been attached yet - in some constructor scenarii + if (md.isConstructor()){ + if ((length != 0) + || (currentToken == TokenNameLBRACE) + // || (currentToken == TokenNamethrows) + ){ + currentElement = currentElement.add(md, 0); + lastIgnoredToken = -1; + } + } + } +} +protected void consumeMethodHeaderThrowsClause() { + // MethodHeaderThrowsClause ::= 'throws' ClassTypeList + int length = astLengthStack[astLengthPtr--]; + astPtr -= length; + AbstractMethodDeclaration md = (AbstractMethodDeclaration) astStack[astPtr]; + System.arraycopy( + astStack, + astPtr + 1, + md.thrownExceptions = new TypeReference[length], + 0, + length); + md.sourceEnd = md.thrownExceptions[length-1].sourceEnd; + md.bodyStart = md.thrownExceptions[length-1].sourceEnd + 1; + listLength = 0; // reset listLength after having read all thrown exceptions + // recovery + if (currentElement != null){ + lastCheckPoint = md.bodyStart; + } +} +protected void consumeMethodInvocationName() { + // MethodInvocation ::= Name '(' ArgumentListopt ')' + + // when the name is only an identifier...we have a message send to "this" (implicit) + + MessageSend m = newMessageSend(); + m.sourceEnd = rParenPos; + m.sourceStart = + (int) ((m.nameSourcePosition = identifierPositionStack[identifierPtr]) >>> 32); + m.selector = identifierStack[identifierPtr--]; + if (identifierLengthStack[identifierLengthPtr] == 1) { + m.receiver = ThisReference.ThisImplicit; + identifierLengthPtr--; + } else { + identifierLengthStack[identifierLengthPtr]--; + m.receiver = getUnspecifiedReference(); + m.sourceStart = m.receiver.sourceStart; + } + pushOnExpressionStack(m); +} +protected void consumeMethodInvocationPrimary() { + //optimize the push/pop + //MethodInvocation ::= Primary '.' 'Identifier' '(' ArgumentListopt ')' + + MessageSend m = newMessageSend(); + m.sourceStart = + (int) ((m.nameSourcePosition = identifierPositionStack[identifierPtr]) >>> 32); + m.selector = identifierStack[identifierPtr--]; + identifierLengthPtr--; + m.receiver = expressionStack[expressionPtr]; + m.sourceStart = m.receiver.sourceStart; + m.sourceEnd = rParenPos; + expressionStack[expressionPtr] = m; +} +protected void consumeMethodInvocationSuper() { + // MethodInvocation ::= 'super' '.' 'Identifier' '(' ArgumentListopt ')' + + MessageSend m = newMessageSend(); + m.sourceStart = intStack[intPtr--]; + m.sourceEnd = rParenPos; + m.nameSourcePosition = identifierPositionStack[identifierPtr]; + m.selector = identifierStack[identifierPtr--]; + identifierLengthPtr--; + m.receiver = new SuperReference(m.sourceStart, endPosition); + pushOnExpressionStack(m); +} +protected void consumeMethodPushModifiersHeaderName() { + // MethodPushModifiersHeaderName ::= Modifiers Type PushModifiers 'Identifier' '(' + // MethodPushModifiersHeaderName ::= Type PushModifiers 'Identifier' '(' + MethodDeclaration md = new MethodDeclaration(this.compilationUnit.compilationResult); + + //name + md.selector = identifierStack[identifierPtr]; + long selectorSource = identifierPositionStack[identifierPtr--]; + identifierLengthPtr--; + + //modifiers + md.declarationSourceStart = intStack[intPtr--]; + md.modifiers = intStack[intPtr--]; + + //type + md.returnType = getTypeReference(intStack[intPtr--]); + + //highlight starts at selector start + md.sourceStart = (int) (selectorSource >>> 32); + pushOnAstStack(md); + md.sourceEnd = lParenPos; + md.bodyStart = lParenPos + 1; + listLength = 0; // initialize listLength before reading parameters/throws + + // recovery + if (currentElement != null) { + lastCheckPoint = md.bodyStart; + currentElement = currentElement.add(md, 0); + lastIgnoredToken = -1; + } +} +protected void consumeModifiers() { + int savedModifiersSourceStart = modifiersSourceStart; + checkAnnotation(); // might update modifiers with AccDeprecated + pushOnIntStack(modifiers); // modifiers + if (modifiersSourceStart >= savedModifiersSourceStart) { + modifiersSourceStart = savedModifiersSourceStart; + } + pushOnIntStack(modifiersSourceStart); + resetModifiers(); +} +protected void consumeNestedMethod() { + // NestedMethod ::= $empty + jumpOverMethodBody(); + nestedMethod[nestedType] ++; + consumeOpenBlock(); +} +protected void consumeNestedType() { + // NestedType ::= $empty + nestedType++; + try { + nestedMethod[nestedType] = 0; + } catch (IndexOutOfBoundsException e) { + //except in test's cases, it should never raise + int oldL = nestedMethod.length; + System.arraycopy(nestedMethod , 0, (nestedMethod = new int[oldL + 30]), 0, oldL); + nestedMethod[nestedType] = 0; + // increase the size of the fieldsCounter as well. It has to be consistent with the size of the nestedMethod collection + System.arraycopy(variablesCounter, 0, (variablesCounter = new int[oldL + 30]), 0, oldL); + } + variablesCounter[nestedType] = 0; +} +protected void consumeOneDimLoop() { + // OneDimLoop ::= '[' ']' + dimensions++; +} +protected void consumeOnlySynchronized() { + // OnlySynchronized ::= 'synchronized' + pushOnIntStack(this.synchronizedBlockSourceStart); + resetModifiers(); +} +protected void consumeOpenBlock() { + // OpenBlock ::= $empty + + pushOnIntStack(scanner.startPosition); + try { + realBlockStack[++realBlockPtr] = 0; + } catch (IndexOutOfBoundsException e) { + //realBlockPtr is correct + int oldStackLength = realBlockStack.length; + int oldStack[] = realBlockStack; + realBlockStack = new int[oldStackLength + StackIncrement]; + System.arraycopy(oldStack, 0, realBlockStack, 0, oldStackLength); + realBlockStack[realBlockPtr] = 0; + } +} +protected void consumePackageDeclaration() { + // PackageDeclaration ::= 'package' Name ';' + /* build an ImportRef build from the last name + stored in the identifier stack. */ + + ImportReference impt = compilationUnit.currentPackage; + // flush annotations defined prior to import statements + impt.declarationEnd = endStatementPosition; + impt.declarationSourceEnd = this.flushAnnotationsDefinedPriorTo(impt.declarationSourceEnd); +} +protected void consumePackageDeclarationName() { + // PackageDeclarationName ::= 'package' Name + /* build an ImportRef build from the last name + stored in the identifier stack. */ + + ImportReference impt; + int length; + char[][] tokens = + new char[length = identifierLengthStack[identifierLengthPtr--]][]; + identifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy(identifierStack, ++identifierPtr, tokens, 0, length); + System.arraycopy( + identifierPositionStack, + identifierPtr--, + positions, + 0, + length); + compilationUnit.currentPackage = + impt = new ImportReference(tokens, positions, true); + + if (currentToken == TokenNameSEMICOLON){ + impt.declarationSourceEnd = scanner.currentPosition - 1; + } else { + impt.declarationSourceEnd = impt.sourceEnd; + } + impt.declarationEnd = impt.declarationSourceEnd; + //endPosition is just before the ; + impt.declarationSourceStart = intStack[intPtr--]; + + // recovery + if (currentElement != null){ + lastCheckPoint = impt.declarationSourceEnd+1; + restartRecovery = true; // used to avoid branching back into the regular automaton + } +} +protected void consumePostfixExpression() { + // PostfixExpression ::= Name + pushOnExpressionStack(getUnspecifiedReferenceOptimized()); +} +protected void consumePrimaryNoNewArray() { + // PrimaryNoNewArray ::= PushLPAREN Expression PushRPAREN + updateSourcePosition(expressionStack[expressionPtr]); +} +protected void consumePrimaryNoNewArrayArrayType() { + // PrimaryNoNewArray ::= ArrayType '.' 'class' + intPtr--; + pushOnExpressionStack( + new ClassLiteralAccess(intStack[intPtr--], + getTypeReference(intStack[intPtr--]))); +} +protected void consumePrimaryNoNewArrayName() { + // PrimaryNoNewArray ::= Name '.' 'class' + intPtr--; + pushOnExpressionStack( + new ClassLiteralAccess(intStack[intPtr--], + getTypeReference(0))); +} +protected void consumePrimaryNoNewArrayNameSuper() { + // PrimaryNoNewArray ::= Name '.' 'super' + pushOnExpressionStack( + new QualifiedSuperReference( + getTypeReference(0), + intStack[intPtr--], + endPosition)); +} +protected void consumePrimaryNoNewArrayNameThis() { + // PrimaryNoNewArray ::= Name '.' 'this' + pushOnExpressionStack( + new QualifiedThisReference( + getTypeReference(0), + intStack[intPtr--], + endPosition)); +} +protected void consumePrimaryNoNewArrayPrimitiveType() { + // PrimaryNoNewArray ::= PrimitiveType '.' 'class' + intPtr--; + pushOnExpressionStack( + new ClassLiteralAccess(intStack[intPtr--], + getTypeReference(0))); +} +protected void consumePrimaryNoNewArrayThis() { + // PrimaryNoNewArray ::= 'this' + pushOnExpressionStack(new ThisReference(intStack[intPtr--], endPosition)); +} +protected void consumePrimitiveType() { + // Type ::= PrimitiveType + pushOnIntStack(0); +} +protected void consumePushModifiers() { + if ((modifiers & AccSynchronized) != 0) { + /* remove the starting position of the synchronized keyword + * we don't need it when synchronized is part of the modifiers + */ + intPtr--; + } + pushOnIntStack(modifiers); // modifiers + pushOnIntStack(modifiersSourceStart); + resetModifiers(); +} +protected void consumePushPosition() { + // for source managment purpose + // PushPosition ::= $empty + pushOnIntStack(endPosition); +} +protected void consumeQualifiedName() { + // QualifiedName ::= Name '.' SimpleName + /*back from the recursive loop of QualifiedName. + Updates identifier length into the length stack*/ + + identifierLengthStack[--identifierLengthPtr]++; +} +protected void consumeReferenceType() { + // ReferenceType ::= ClassOrInterfaceType + pushOnIntStack(0); +} +protected void consumeRestoreDiet() { + // RestoreDiet ::= $empty + dietInt--; +} +protected void consumeRightParen() { + // PushRPAREN ::= ')' + pushOnIntStack(rParenPos); +} + // This method is part of an automatic generation : do NOT edit-modify + // This method is part of an automatic generation : do NOT edit-modify + protected void consumeRule(int act) { + switch ( act ) { + case 29 : // System.out.println("Type ::= PrimitiveType"); + consumePrimitiveType(); + break ; + + case 43 : // System.out.println("ReferenceType ::= ClassOrInterfaceType"); + consumeReferenceType(); + break ; + + case 52 : // System.out.println("QualifiedName ::= Name DOT SimpleName"); + consumeQualifiedName(); + break ; + + case 53 : // System.out.println("CompilationUnit ::= EnterCompilationUnit PackageDeclarationopt ImportDeclarationsopt"); + consumeCompilationUnit(); + break ; + + case 54 : // System.out.println("EnterCompilationUnit ::="); + consumeEnterCompilationUnit(); + break ; + + case 66 : // System.out.println("CatchHeader ::= catch LPAREN FormalParameter RPAREN LBRACE"); + consumeCatchHeader(); + break ; + + case 68 : // System.out.println("ImportDeclarations ::= ImportDeclarations ImportDeclaration"); + consumeImportDeclarations(); + break ; + + case 70 : // System.out.println("TypeDeclarations ::= TypeDeclarations TypeDeclaration"); + consumeTypeDeclarations(); + break ; + + case 71 : // System.out.println("PackageDeclaration ::= PackageDeclarationName SEMICOLON"); + consumePackageDeclaration(); + break ; + + case 72 : // System.out.println("PackageDeclarationName ::= package Name"); + consumePackageDeclarationName(); + break ; + + case 75 : // System.out.println("SingleTypeImportDeclaration ::= SingleTypeImportDeclarationName SEMICOLON"); + consumeSingleTypeImportDeclaration(); + break ; + + case 76 : // System.out.println("SingleTypeImportDeclarationName ::= import Name"); + consumeSingleTypeImportDeclarationName(); + break ; + + case 77 : // System.out.println("TypeImportOnDemandDeclaration ::= TypeImportOnDemandDeclarationName SEMICOLON"); + consumeTypeImportOnDemandDeclaration(); + break ; + + case 78 : // System.out.println("TypeImportOnDemandDeclarationName ::= import Name DOT MULTIPLY"); + consumeTypeImportOnDemandDeclarationName(); + break ; + + case 81 : // System.out.println("TypeDeclaration ::= SEMICOLON"); + consumeEmptyTypeDeclaration(); + break ; + + case 95 : // System.out.println("ClassDeclaration ::= ClassHeader ClassBody"); + consumeClassDeclaration(); + break ; + + case 96 : // System.out.println("ClassHeader ::= ClassHeaderName ClassHeaderExtendsopt ClassHeaderImplementsopt"); + consumeClassHeader(); + break ; + + case 97 : // System.out.println("ClassHeaderName ::= Modifiersopt class Identifier"); + consumeClassHeaderName(); + break ; + + case 98 : // System.out.println("ClassHeaderExtends ::= extends ClassType"); + consumeClassHeaderExtends(); + break ; + + case 99 : // System.out.println("ClassHeaderImplements ::= implements InterfaceTypeList"); + consumeClassHeaderImplements(); + break ; + + case 101 : // System.out.println("InterfaceTypeList ::= InterfaceTypeList COMMA InterfaceType"); + consumeInterfaceTypeList(); + break ; + + case 102 : // System.out.println("InterfaceType ::= ClassOrInterfaceType"); + consumeInterfaceType(); + break ; + + case 105 : // System.out.println("ClassBodyDeclarations ::= ClassBodyDeclarations ClassBodyDeclaration"); + consumeClassBodyDeclarations(); + break ; + + case 109 : // System.out.println("ClassBodyDeclaration ::= Diet NestedMethod Block"); + consumeClassBodyDeclaration(); + break ; + + case 110 : // System.out.println("Diet ::="); + consumeDiet(); + break ; + + case 111 : // System.out.println("Initializer ::= Diet NestedMethod Block"); + consumeClassBodyDeclaration(); + break ; + + case 118 : // System.out.println("ClassMemberDeclaration ::= SEMICOLON"); + consumeEmptyClassMemberDeclaration(); + break ; + + case 119 : // System.out.println("FieldDeclaration ::= Modifiersopt Type VariableDeclarators SEMICOLON"); + consumeFieldDeclaration(); + break ; + + case 121 : // System.out.println("VariableDeclarators ::= VariableDeclarators COMMA VariableDeclarator"); + consumeVariableDeclarators(); + break ; + + case 124 : // System.out.println("EnterVariable ::="); + consumeEnterVariable(); + break ; + + case 125 : // System.out.println("ExitVariableWithInitialization ::="); + consumeExitVariableWithInitialization(); + break ; + + case 126 : // System.out.println("ExitVariableWithoutInitialization ::="); + consumeExitVariableWithoutInitialization(); + break ; + + case 127 : // System.out.println("ForceNoDiet ::="); + consumeForceNoDiet(); + break ; + + case 128 : // System.out.println("RestoreDiet ::="); + consumeRestoreDiet(); + break ; + + case 133 : // System.out.println("MethodDeclaration ::= MethodHeader MethodBody"); + // set to true to consume a method with a body + consumeMethodDeclaration(true); + break ; + + case 134 : // System.out.println("AbstractMethodDeclaration ::= MethodHeader SEMICOLON"); + // set to false to consume a method without body + consumeMethodDeclaration(false); + break ; + + case 135 : // System.out.println("MethodHeader ::= MethodHeaderName MethodHeaderParameters MethodHeaderExtendedDims"); + consumeMethodHeader(); + break ; + + case 136 : // System.out.println("MethodPushModifiersHeader ::= MethodPushModifiersHeaderName MethodHeaderParameters"); + consumeMethodHeader(); + break ; + + case 137 : // System.out.println("MethodPushModifiersHeaderName ::= Modifiers Type PushModifiers Identifier LPAREN"); + consumeMethodPushModifiersHeaderName(); + break ; + + case 138 : // System.out.println("MethodPushModifiersHeaderName ::= Type PushModifiers Identifier LPAREN"); + consumeMethodPushModifiersHeaderName(); + break ; + + case 139 : // System.out.println("MethodHeaderName ::= Modifiersopt Type Identifier LPAREN"); + consumeMethodHeaderName(); + break ; + + case 140 : // System.out.println("MethodHeaderParameters ::= FormalParameterListopt RPAREN"); + consumeMethodHeaderParameters(); + break ; + + case 141 : // System.out.println("MethodHeaderExtendedDims ::= Dimsopt"); + consumeMethodHeaderExtendedDims(); + break ; + + case 142 : // System.out.println("MethodHeaderThrowsClause ::= throws ClassTypeList"); + consumeMethodHeaderThrowsClause(); + break ; + + case 143 : // System.out.println("ConstructorHeader ::= ConstructorHeaderName MethodHeaderParameters..."); + consumeConstructorHeader(); + break ; + + case 144 : // System.out.println("ConstructorHeaderName ::= Modifiersopt Identifier LPAREN"); + consumeConstructorHeaderName(); + break ; + + case 146 : // System.out.println("FormalParameterList ::= FormalParameterList COMMA FormalParameter"); + consumeFormalParameterList(); + break ; + + case 147 : // System.out.println("FormalParameter ::= Modifiersopt Type VariableDeclaratorId"); + // the boolean is used to know if the modifiers should be reset + consumeFormalParameter(); + break ; + + case 149 : // System.out.println("ClassTypeList ::= ClassTypeList COMMA ClassTypeElt"); + consumeClassTypeList(); + break ; + + case 150 : // System.out.println("ClassTypeElt ::= ClassType"); + consumeClassTypeElt(); + break ; + + case 151 : // System.out.println("MethodBody ::= NestedMethod LBRACE BlockStatementsopt RBRACE"); + consumeMethodBody(); + break ; + + case 152 : // System.out.println("NestedMethod ::="); + consumeNestedMethod(); + break ; + + case 153 : // System.out.println("StaticInitializer ::= StaticOnly Block"); + consumeStaticInitializer(); + break ; + + case 154 : // System.out.println("StaticOnly ::= static"); + consumeStaticOnly(); + break ; + + case 155 : // System.out.println("ConstructorDeclaration ::= ConstructorHeader ConstructorBody"); + consumeConstructorDeclaration() ; + break ; + + case 156 : // System.out.println("ConstructorDeclaration ::= ConstructorHeader SEMICOLON"); + consumeInvalidConstructorDeclaration() ; + break ; + + case 157 : // System.out.println("ConstructorBody ::= NestedMethod LBRACE ConstructorBlockStatementsopt RBRACE"); + consumeConstructorBody(); + break ; + + case 160 : // System.out.println("ConstructorBlockStatementsopt ::= ExplicitConstructorInvocation BlockStatements"); + consumeConstructorBlockStatements(); + break ; + + case 161 : // System.out.println("ExplicitConstructorInvocation ::= this LPAREN ArgumentListopt RPAREN SEMICOLON"); + consumeExplicitConstructorInvocation(0,ExplicitConstructorCall.This); + break ; + + case 162 : // System.out.println("ExplicitConstructorInvocation ::= super LPAREN ArgumentListopt RPAREN SEMICOLON"); + consumeExplicitConstructorInvocation(0,ExplicitConstructorCall.Super); + break ; + + case 163 : // System.out.println("ExplicitConstructorInvocation ::= Primary DOT super LPAREN ArgumentListopt RPAREN"); + consumeExplicitConstructorInvocation(1, ExplicitConstructorCall.Super); + break ; + + case 164 : // System.out.println("ExplicitConstructorInvocation ::= Name DOT super LPAREN ArgumentListopt RPAREN..."); + consumeExplicitConstructorInvocation(2, ExplicitConstructorCall.Super); + break ; + + case 165 : // System.out.println("ExplicitConstructorInvocation ::= Primary DOT this LPAREN ArgumentListopt RPAREN..."); + consumeExplicitConstructorInvocation(1, ExplicitConstructorCall.This); + break ; + + case 166 : // System.out.println("ExplicitConstructorInvocation ::= Name DOT this LPAREN ArgumentListopt RPAREN..."); + consumeExplicitConstructorInvocation(2, ExplicitConstructorCall.This); + break ; + + case 167 : // System.out.println("InterfaceDeclaration ::= InterfaceHeader InterfaceBody"); + consumeInterfaceDeclaration(); + break ; + + case 168 : // System.out.println("InterfaceHeader ::= InterfaceHeaderName InterfaceHeaderExtendsopt"); + consumeInterfaceHeader(); + break ; + + case 169 : // System.out.println("InterfaceHeaderName ::= Modifiersopt interface Identifier"); + consumeInterfaceHeaderName(); + break ; + + case 171 : // System.out.println("InterfaceHeaderExtends ::= extends InterfaceTypeList"); + consumeInterfaceHeaderExtends(); + break ; + + case 174 : // System.out.println("InterfaceMemberDeclarations ::= InterfaceMemberDeclarations..."); + consumeInterfaceMemberDeclarations(); + break ; + + case 175 : // System.out.println("InterfaceMemberDeclaration ::= SEMICOLON"); + consumeEmptyInterfaceMemberDeclaration(); + break ; + + case 178 : // System.out.println("InterfaceMemberDeclaration ::= InvalidMethodDeclaration"); + ignoreMethodBody(); + break ; + + case 179 : // System.out.println("InvalidConstructorDeclaration ::= ConstructorHeader ConstructorBody"); + ignoreInvalidConstructorDeclaration(true); + break ; + + case 180 : // System.out.println("InvalidConstructorDeclaration ::= ConstructorHeader SEMICOLON"); + ignoreInvalidConstructorDeclaration(false); + break ; + + case 186 : // System.out.println("ArrayInitializer ::= LBRACE ,opt RBRACE"); + consumeEmptyArrayInitializer(); + break ; + + case 187 : // System.out.println("ArrayInitializer ::= LBRACE VariableInitializers RBRACE"); + consumeArrayInitializer(); + break ; + + case 188 : // System.out.println("ArrayInitializer ::= LBRACE VariableInitializers COMMA RBRACE"); + consumeArrayInitializer(); + break ; + + case 190 : // System.out.println("VariableInitializers ::= VariableInitializers COMMA VariableInitializer"); + consumeVariableInitializers(); + break ; + + case 191 : // System.out.println("Block ::= OpenBlock LBRACE BlockStatementsopt RBRACE"); + consumeBlock(); + break ; + + case 192 : // System.out.println("OpenBlock ::="); + consumeOpenBlock() ; + break ; + + case 194 : // System.out.println("BlockStatements ::= BlockStatements BlockStatement"); + consumeBlockStatements() ; + break ; + + case 198 : // System.out.println("BlockStatement ::= InvalidInterfaceDeclaration"); + ignoreInterfaceDeclaration(); + break ; + + case 199 : // System.out.println("LocalVariableDeclarationStatement ::= LocalVariableDeclaration SEMICOLON"); + consumeLocalVariableDeclarationStatement(); + break ; + + case 200 : // System.out.println("LocalVariableDeclaration ::= Type PushModifiers VariableDeclarators"); + consumeLocalVariableDeclaration(); + break ; + + case 201 : // System.out.println("LocalVariableDeclaration ::= Modifiers Type PushModifiers VariableDeclarators"); + consumeLocalVariableDeclaration(); + break ; + + case 202 : // System.out.println("PushModifiers ::="); + consumePushModifiers(); + break ; + + case 226 : // System.out.println("EmptyStatement ::= SEMICOLON"); + consumeEmptyStatement(); + break ; + + case 227 : // System.out.println("LabeledStatement ::= Identifier COLON Statement"); + consumeStatementLabel() ; + break ; + + case 228 : // System.out.println("LabeledStatementNoShortIf ::= Identifier COLON StatementNoShortIf"); + consumeStatementLabel() ; + break ; + + case 229 : // System.out.println("ExpressionStatement ::= StatementExpression SEMICOLON"); + consumeExpressionStatement(); + break ; + + case 237 : // System.out.println("IfThenStatement ::= if LPAREN Expression RPAREN Statement"); + consumeStatementIfNoElse(); + break ; + + case 238 : // System.out.println("IfThenElseStatement ::= if LPAREN Expression RPAREN StatementNoShortIf else..."); + consumeStatementIfWithElse(); + break ; + + case 239 : // System.out.println("IfThenElseStatementNoShortIf ::= if LPAREN Expression RPAREN StatementNoShortIf..."); + consumeStatementIfWithElse(); + break ; + + case 240 : // System.out.println("SwitchStatement ::= switch OpenBlock LPAREN Expression RPAREN SwitchBlock"); + consumeStatementSwitch() ; + break ; + + case 241 : // System.out.println("SwitchBlock ::= LBRACE RBRACE"); + consumeEmptySwitchBlock() ; + break ; + + case 244 : // System.out.println("SwitchBlock ::= LBRACE SwitchBlockStatements SwitchLabels RBRACE"); + consumeSwitchBlock() ; + break ; + + case 246 : // System.out.println("SwitchBlockStatements ::= SwitchBlockStatements SwitchBlockStatement"); + consumeSwitchBlockStatements() ; + break ; + + case 247 : // System.out.println("SwitchBlockStatement ::= SwitchLabels BlockStatements"); + consumeSwitchBlockStatement() ; + break ; + + case 249 : // System.out.println("SwitchLabels ::= SwitchLabels SwitchLabel"); + consumeSwitchLabels() ; + break ; + + case 250 : // System.out.println("SwitchLabel ::= case ConstantExpression COLON"); + consumeCaseLabel(); + break ; + + case 251 : // System.out.println("SwitchLabel ::= default COLON"); + consumeDefaultLabel(); + break ; + + case 252 : // System.out.println("WhileStatement ::= while LPAREN Expression RPAREN Statement"); + consumeStatementWhile() ; + break ; + + case 253 : // System.out.println("WhileStatementNoShortIf ::= while LPAREN Expression RPAREN StatementNoShortIf"); + consumeStatementWhile() ; + break ; + + case 254 : // System.out.println("DoStatement ::= do Statement while LPAREN Expression RPAREN SEMICOLON"); + consumeStatementDo() ; + break ; + + case 255 : // System.out.println("ForStatement ::= for LPAREN ForInitopt SEMICOLON Expressionopt SEMICOLON..."); + consumeStatementFor() ; + break ; + + case 256 : // System.out.println("ForStatementNoShortIf ::= for LPAREN ForInitopt SEMICOLON Expressionopt SEMICOLON"); + consumeStatementFor() ; + break ; + + case 257 : // System.out.println("ForInit ::= StatementExpressionList"); + consumeForInit() ; + break ; + + case 261 : // System.out.println("StatementExpressionList ::= StatementExpressionList COMMA StatementExpression"); + consumeStatementExpressionList() ; + break ; + + case 262 : // System.out.println("AssertStatement ::= assert Expression SEMICOLON"); + consumeSimpleAssertStatement() ; + break ; + + case 263 : // System.out.println("AssertStatement ::= assert Expression COLON Expression SEMICOLON"); + consumeAssertStatement() ; + break ; + + case 264 : // System.out.println("BreakStatement ::= break SEMICOLON"); + consumeStatementBreak() ; + break ; + + case 265 : // System.out.println("BreakStatement ::= break Identifier SEMICOLON"); + consumeStatementBreakWithLabel() ; + break ; + + case 266 : // System.out.println("ContinueStatement ::= continue SEMICOLON"); + consumeStatementContinue() ; + break ; + + case 267 : // System.out.println("ContinueStatement ::= continue Identifier SEMICOLON"); + consumeStatementContinueWithLabel() ; + break ; + + case 268 : // System.out.println("ReturnStatement ::= return Expressionopt SEMICOLON"); + consumeStatementReturn() ; + break ; + + case 269 : // System.out.println("ThrowStatement ::= throw Expression SEMICOLON"); + consumeStatementThrow(); + + break ; + + case 270 : // System.out.println("SynchronizedStatement ::= OnlySynchronized LPAREN Expression RPAREN Block"); + consumeStatementSynchronized(); + break ; + + case 271 : // System.out.println("OnlySynchronized ::= synchronized"); + consumeOnlySynchronized(); + break ; + + case 272 : // System.out.println("TryStatement ::= try Block Catches"); + consumeStatementTry(false); + break ; + + case 273 : // System.out.println("TryStatement ::= try Block Catchesopt Finally"); + consumeStatementTry(true); + break ; + + case 275 : // System.out.println("Catches ::= Catches CatchClause"); + consumeCatches(); + break ; + + case 276 : // System.out.println("CatchClause ::= catch LPAREN FormalParameter RPAREN Block"); + consumeStatementCatch() ; + break ; + + case 278 : // System.out.println("PushLPAREN ::= LPAREN"); + consumeLeftParen(); + break ; + + case 279 : // System.out.println("PushRPAREN ::= RPAREN"); + consumeRightParen(); + break ; + + case 283 : // System.out.println("PrimaryNoNewArray ::= this"); + consumePrimaryNoNewArrayThis(); + break ; + + case 284 : // System.out.println("PrimaryNoNewArray ::= PushLPAREN Expression PushRPAREN"); + consumePrimaryNoNewArray(); + break ; + + case 287 : // System.out.println("PrimaryNoNewArray ::= Name DOT this"); + consumePrimaryNoNewArrayNameThis(); + break ; + + case 288 : // System.out.println("PrimaryNoNewArray ::= Name DOT super"); + consumePrimaryNoNewArrayNameSuper(); + break ; + + case 289 : // System.out.println("PrimaryNoNewArray ::= Name DOT class"); + consumePrimaryNoNewArrayName(); + break ; + + case 290 : // System.out.println("PrimaryNoNewArray ::= ArrayType DOT class"); + consumePrimaryNoNewArrayArrayType(); + break ; + + case 291 : // System.out.println("PrimaryNoNewArray ::= PrimitiveType DOT class"); + consumePrimaryNoNewArrayPrimitiveType(); + break ; + + case 294 : // System.out.println("AllocationHeader ::= new ClassType LPAREN ArgumentListopt RPAREN"); + consumeAllocationHeader(); + break ; + + case 295 : // System.out.println("ClassInstanceCreationExpression ::= new ClassType LPAREN ArgumentListopt RPAREN..."); + consumeClassInstanceCreationExpression(); + break ; + + case 296 : // System.out.println("ClassInstanceCreationExpression ::= Primary DOT new SimpleName LPAREN..."); + consumeClassInstanceCreationExpressionQualified() ; + break ; + + case 297 : // System.out.println("ClassInstanceCreationExpression ::= ClassInstanceCreationExpressionName new..."); + consumeClassInstanceCreationExpressionQualified() ; + break ; + + case 298 : // System.out.println("ClassInstanceCreationExpressionName ::= Name DOT"); + consumeClassInstanceCreationExpressionName() ; + break ; + + case 299 : // System.out.println("ClassBodyopt ::="); + consumeClassBodyopt(); + break ; + + case 301 : // System.out.println("EnterAnonymousClassBody ::="); + consumeEnterAnonymousClassBody(); + break ; + + case 303 : // System.out.println("ArgumentList ::= ArgumentList COMMA Expression"); + consumeArgumentList(); + break ; + + case 304 : // System.out.println("ArrayCreationExpression ::= new PrimitiveType DimWithOrWithOutExprs..."); + consumeArrayCreationExpression(); + break ; + + case 305 : // System.out.println("ArrayCreationExpression ::= new ClassOrInterfaceType DimWithOrWithOutExprs..."); + consumeArrayCreationExpression(); + break ; + + case 307 : // System.out.println("DimWithOrWithOutExprs ::= DimWithOrWithOutExprs DimWithOrWithOutExpr"); + consumeDimWithOrWithOutExprs(); + break ; + + case 309 : // System.out.println("DimWithOrWithOutExpr ::= LBRACKET RBRACKET"); + consumeDimWithOrWithOutExpr(); + break ; + + case 310 : // System.out.println("Dims ::= DimsLoop"); + consumeDims(); + break ; + + case 313 : // System.out.println("OneDimLoop ::= LBRACKET RBRACKET"); + consumeOneDimLoop(); + break ; + + case 314 : // System.out.println("FieldAccess ::= Primary DOT Identifier"); + consumeFieldAccess(false); + break ; + + case 315 : // System.out.println("FieldAccess ::= super DOT Identifier"); + consumeFieldAccess(true); + break ; + + case 316 : // System.out.println("MethodInvocation ::= Name LPAREN ArgumentListopt RPAREN"); + consumeMethodInvocationName(); + break ; + + case 317 : // System.out.println("MethodInvocation ::= Primary DOT Identifier LPAREN ArgumentListopt RPAREN"); + consumeMethodInvocationPrimary(); + break ; + + case 318 : // System.out.println("MethodInvocation ::= super DOT Identifier LPAREN ArgumentListopt RPAREN"); + consumeMethodInvocationSuper(); + break ; + + case 319 : // System.out.println("ArrayAccess ::= Name LBRACKET Expression RBRACKET"); + consumeArrayAccess(true); + break ; + + case 320 : // System.out.println("ArrayAccess ::= PrimaryNoNewArray LBRACKET Expression RBRACKET"); + consumeArrayAccess(false); + break ; + + case 322 : // System.out.println("PostfixExpression ::= Name"); + consumePostfixExpression(); + break ; + + case 325 : // System.out.println("PostIncrementExpression ::= PostfixExpression PLUS_PLUS"); + consumeUnaryExpression(OperatorExpression.PLUS,true); + break ; + + case 326 : // System.out.println("PostDecrementExpression ::= PostfixExpression MINUS_MINUS"); + consumeUnaryExpression(OperatorExpression.MINUS,true); + break ; + + case 327 : // System.out.println("PushPosition ::="); + consumePushPosition(); + break ; + + case 330 : // System.out.println("UnaryExpression ::= PLUS PushPosition UnaryExpression"); + consumeUnaryExpression(OperatorExpression.PLUS); + break ; + + case 331 : // System.out.println("UnaryExpression ::= MINUS PushPosition UnaryExpression"); + consumeUnaryExpression(OperatorExpression.MINUS); + break ; + + case 333 : // System.out.println("PreIncrementExpression ::= PLUS_PLUS PushPosition UnaryExpression"); + consumeUnaryExpression(OperatorExpression.PLUS,false); + break ; + + case 334 : // System.out.println("PreDecrementExpression ::= MINUS_MINUS PushPosition UnaryExpression"); + consumeUnaryExpression(OperatorExpression.MINUS,false); + break ; + + case 336 : // System.out.println("UnaryExpressionNotPlusMinus ::= TWIDDLE PushPosition UnaryExpression"); + consumeUnaryExpression(OperatorExpression.TWIDDLE); + break ; + + case 337 : // System.out.println("UnaryExpressionNotPlusMinus ::= NOT PushPosition UnaryExpression"); + consumeUnaryExpression(OperatorExpression.NOT); + break ; + + case 339 : // System.out.println("CastExpression ::= PushLPAREN PrimitiveType Dimsopt PushRPAREN UnaryExpression"); + consumeCastExpression(); + break ; + + case 340 : // System.out.println("CastExpression ::= PushLPAREN Name Dims PushRPAREN UnaryExpressionNotPlusMinus"); + consumeCastExpression(); + break ; + + case 341 : // System.out.println("CastExpression ::= PushLPAREN Expression PushRPAREN UnaryExpressionNotPlusMinus"); + consumeCastExpressionLL1(); + break ; + + case 343 : // System.out.println("MultiplicativeExpression ::= MultiplicativeExpression MULTIPLY UnaryExpression"); + consumeBinaryExpression(OperatorExpression.MULTIPLY); + break ; + + case 344 : // System.out.println("MultiplicativeExpression ::= MultiplicativeExpression DIVIDE UnaryExpression"); + consumeBinaryExpression(OperatorExpression.DIVIDE); + break ; + + case 345 : // System.out.println("MultiplicativeExpression ::= MultiplicativeExpression REMAINDER UnaryExpression"); + consumeBinaryExpression(OperatorExpression.REMAINDER); + break ; + + case 347 : // System.out.println("AdditiveExpression ::= AdditiveExpression PLUS MultiplicativeExpression"); + consumeBinaryExpression(OperatorExpression.PLUS); + break ; + + case 348 : // System.out.println("AdditiveExpression ::= AdditiveExpression MINUS MultiplicativeExpression"); + consumeBinaryExpression(OperatorExpression.MINUS); + break ; + + case 350 : // System.out.println("ShiftExpression ::= ShiftExpression LEFT_SHIFT AdditiveExpression"); + consumeBinaryExpression(OperatorExpression.LEFT_SHIFT); + break ; + + case 351 : // System.out.println("ShiftExpression ::= ShiftExpression RIGHT_SHIFT AdditiveExpression"); + consumeBinaryExpression(OperatorExpression.RIGHT_SHIFT); + break ; + + case 352 : // System.out.println("ShiftExpression ::= ShiftExpression UNSIGNED_RIGHT_SHIFT AdditiveExpression"); + consumeBinaryExpression(OperatorExpression.UNSIGNED_RIGHT_SHIFT); + break ; + + case 354 : // System.out.println("RelationalExpression ::= RelationalExpression LESS ShiftExpression"); + consumeBinaryExpression(OperatorExpression.LESS); + break ; + + case 355 : // System.out.println("RelationalExpression ::= RelationalExpression GREATER ShiftExpression"); + consumeBinaryExpression(OperatorExpression.GREATER); + break ; + + case 356 : // System.out.println("RelationalExpression ::= RelationalExpression LESS_EQUAL ShiftExpression"); + consumeBinaryExpression(OperatorExpression.LESS_EQUAL); + break ; + + case 357 : // System.out.println("RelationalExpression ::= RelationalExpression GREATER_EQUAL ShiftExpression"); + consumeBinaryExpression(OperatorExpression.GREATER_EQUAL); + break ; + + case 358 : // System.out.println("RelationalExpression ::= RelationalExpression instanceof ReferenceType"); + consumeInstanceOfExpression(OperatorExpression.INSTANCEOF); + break ; + + case 360 : // System.out.println("EqualityExpression ::= EqualityExpression EQUAL_EQUAL RelationalExpression"); + consumeEqualityExpression(OperatorExpression.EQUAL_EQUAL); + break ; + + case 361 : // System.out.println("EqualityExpression ::= EqualityExpression NOT_EQUAL RelationalExpression"); + consumeEqualityExpression(OperatorExpression.NOT_EQUAL); + break ; + + case 363 : // System.out.println("AndExpression ::= AndExpression AND EqualityExpression"); + consumeBinaryExpression(OperatorExpression.AND); + break ; + + case 365 : // System.out.println("ExclusiveOrExpression ::= ExclusiveOrExpression XOR AndExpression"); + consumeBinaryExpression(OperatorExpression.XOR); + break ; + + case 367 : // System.out.println("InclusiveOrExpression ::= InclusiveOrExpression OR ExclusiveOrExpression"); + consumeBinaryExpression(OperatorExpression.OR); + break ; + + case 369 : // System.out.println("ConditionalAndExpression ::= ConditionalAndExpression AND_AND InclusiveOrExpression"); + consumeBinaryExpression(OperatorExpression.AND_AND); + break ; + + case 371 : // System.out.println("ConditionalOrExpression ::= ConditionalOrExpression OR_OR ConditionalAndExpression"); + consumeBinaryExpression(OperatorExpression.OR_OR); + break ; + + case 373 : // System.out.println("ConditionalExpression ::= ConditionalOrExpression QUESTION Expression COLON..."); + consumeConditionalExpression(OperatorExpression.QUESTIONCOLON) ; + break ; + + case 376 : // System.out.println("Assignment ::= LeftHandSide AssignmentOperator AssignmentExpression"); + consumeAssignment(); + break ; + + case 378 : // System.out.println("Assignment ::= InvalidArrayInitializerAssignement"); + ignoreExpressionAssignment(); + break ; + + case 379 : // System.out.println("LeftHandSide ::= Name"); + consumeLeftHandSide(); + break ; + + case 382 : // System.out.println("AssignmentOperator ::= EQUAL"); + consumeAssignmentOperator(EQUAL); + break ; + + case 383 : // System.out.println("AssignmentOperator ::= MULTIPLY_EQUAL"); + consumeAssignmentOperator(MULTIPLY); + break ; + + case 384 : // System.out.println("AssignmentOperator ::= DIVIDE_EQUAL"); + consumeAssignmentOperator(DIVIDE); + break ; + + case 385 : // System.out.println("AssignmentOperator ::= REMAINDER_EQUAL"); + consumeAssignmentOperator(REMAINDER); + break ; + + case 386 : // System.out.println("AssignmentOperator ::= PLUS_EQUAL"); + consumeAssignmentOperator(PLUS); + break ; + + case 387 : // System.out.println("AssignmentOperator ::= MINUS_EQUAL"); + consumeAssignmentOperator(MINUS); + break ; + + case 388 : // System.out.println("AssignmentOperator ::= LEFT_SHIFT_EQUAL"); + consumeAssignmentOperator(LEFT_SHIFT); + break ; + + case 389 : // System.out.println("AssignmentOperator ::= RIGHT_SHIFT_EQUAL"); + consumeAssignmentOperator(RIGHT_SHIFT); + break ; + + case 390 : // System.out.println("AssignmentOperator ::= UNSIGNED_RIGHT_SHIFT_EQUAL"); + consumeAssignmentOperator(UNSIGNED_RIGHT_SHIFT); + break ; + + case 391 : // System.out.println("AssignmentOperator ::= AND_EQUAL"); + consumeAssignmentOperator(AND); + break ; + + case 392 : // System.out.println("AssignmentOperator ::= XOR_EQUAL"); + consumeAssignmentOperator(XOR); + break ; + + case 393 : // System.out.println("AssignmentOperator ::= OR_EQUAL"); + consumeAssignmentOperator(OR); + break ; + + case 400 : // System.out.println("Expressionopt ::="); + consumeEmptyExpression(); + break ; + + case 404 : // System.out.println("ImportDeclarationsopt ::="); + consumeEmptyImportDeclarationsopt(); + break ; + + case 405 : // System.out.println("ImportDeclarationsopt ::= ImportDeclarations"); + consumeImportDeclarationsopt(); + break ; + + case 406 : // System.out.println("TypeDeclarationsopt ::="); + consumeEmptyTypeDeclarationsopt(); + break ; + + case 407 : // System.out.println("TypeDeclarationsopt ::= TypeDeclarations"); + consumeTypeDeclarationsopt(); + break ; + + case 408 : // System.out.println("ClassBodyDeclarationsopt ::="); + consumeEmptyClassBodyDeclarationsopt(); + break ; + + case 409 : // System.out.println("ClassBodyDeclarationsopt ::= NestedType ClassBodyDeclarations"); + consumeClassBodyDeclarationsopt(); + break ; + + case 410 : // System.out.println("Modifiersopt ::="); + consumeDefaultModifiers(); + break ; + + case 411 : // System.out.println("Modifiersopt ::= Modifiers"); + consumeModifiers(); + break ; + + case 412 : // System.out.println("BlockStatementsopt ::="); + consumeEmptyBlockStatementsopt(); + break ; + + case 414 : // System.out.println("Dimsopt ::="); + consumeEmptyDimsopt(); + break ; + + case 416 : // System.out.println("ArgumentListopt ::="); + consumeEmptyArgumentListopt(); + break ; + + case 420 : // System.out.println("FormalParameterListopt ::="); + consumeFormalParameterListopt(); + break ; + + case 424 : // System.out.println("InterfaceMemberDeclarationsopt ::="); + consumeEmptyInterfaceMemberDeclarationsopt(); + break ; + + case 425 : // System.out.println("InterfaceMemberDeclarationsopt ::= NestedType InterfaceMemberDeclarations"); + consumeInterfaceMemberDeclarationsopt(); + break ; + + case 426 : // System.out.println("NestedType ::="); + consumeNestedType(); + break ; + + case 427 : // System.out.println("ForInitopt ::="); + consumeEmptyForInitopt(); + break ; + + case 429 : // System.out.println("ForUpdateopt ::="); + consumeEmptyForUpdateopt(); + break ; + + case 433 : // System.out.println("Catchesopt ::="); + consumeEmptyCatchesopt(); + break ; + + case 435 : // System.out.println("ArrayInitializeropt ::="); + consumeEmptyArrayInitializeropt(); + break ; + + } + } + + +protected void consumeSimpleAssertStatement() { + // AssertStatement ::= 'assert' Expression ';' + expressionLengthPtr--; + pushOnAstStack(new AssertStatement(expressionStack[expressionPtr--], intStack[intPtr--])); +} + +protected void consumeSingleTypeImportDeclaration() { + // SingleTypeImportDeclaration ::= SingleTypeImportDeclarationName ';' + + ImportReference impt = (ImportReference) astStack[astPtr]; + // flush annotations defined prior to import statements + impt.declarationEnd = endStatementPosition; + impt.declarationSourceEnd = + this.flushAnnotationsDefinedPriorTo(impt.declarationSourceEnd); + + // recovery + if (currentElement != null) { + lastCheckPoint = impt.declarationSourceEnd + 1; + currentElement = currentElement.add(impt, 0); + lastIgnoredToken = -1; + restartRecovery = true; + // used to avoid branching back into the regular automaton + } +} +protected void consumeSingleTypeImportDeclarationName() { + // SingleTypeImportDeclarationName ::= 'import' Name + /* push an ImportRef build from the last name + stored in the identifier stack. */ + + ImportReference impt; + int length; + char[][] tokens = new char[length = identifierLengthStack[identifierLengthPtr--]][]; + identifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length); + System.arraycopy(identifierPositionStack, identifierPtr + 1, positions, 0, length); + pushOnAstStack(impt = new ImportReference(tokens, positions, false)); + + if (currentToken == TokenNameSEMICOLON){ + impt.declarationSourceEnd = scanner.currentPosition - 1; + } else { + impt.declarationSourceEnd = impt.sourceEnd; + } + impt.declarationEnd = impt.declarationSourceEnd; + //endPosition is just before the ; + impt.declarationSourceStart = intStack[intPtr--]; + + // recovery + if (currentElement != null){ + lastCheckPoint = impt.declarationSourceEnd+1; + currentElement = currentElement.add(impt, 0); + lastIgnoredToken = -1; + restartRecovery = true; // used to avoid branching back into the regular automaton + } +} +protected void consumeStatementBreak() { + // BreakStatement ::= 'break' ';' + // break pushs a position on intStack in case there is no label + + pushOnAstStack(new Break(null, intStack[intPtr--], endPosition)); +} +protected void consumeStatementBreakWithLabel() { + // BreakStatement ::= 'break' Identifier ';' + // break pushs a position on intStack in case there is no label + + pushOnAstStack( + new Break( + identifierStack[identifierPtr--], + intStack[intPtr--], + endPosition)); + identifierLengthPtr--; +} +protected void consumeStatementCatch() { + // CatchClause ::= 'catch' '(' FormalParameter ')' Block + + //catch are stored directly into the Try + //has they always comes two by two.... + //we remove one entry from the astlengthPtr. + //The construction of the try statement must + //then fetch the catches using 2*i and 2*i + 1 + + astLengthPtr--; + listLength = 0; // reset formalParameter counter (incremented for catch variable) +} +protected void consumeStatementContinue() { + // ContinueStatement ::= 'continue' ';' + // continue pushs a position on intStack in case there is no label + + pushOnAstStack( + new Continue( + null, + intStack[intPtr--], + endPosition)); +} +protected void consumeStatementContinueWithLabel() { + // ContinueStatement ::= 'continue' Identifier ';' + // continue pushs a position on intStack in case there is no label + + pushOnAstStack( + new Continue( + identifierStack[identifierPtr--], + intStack[intPtr--], + endPosition)); + identifierLengthPtr--; +} +protected void consumeStatementDo() { + // DoStatement ::= 'do' Statement 'while' '(' Expression ')' ';' + + //the 'while' pushes a value on intStack that we need to remove + intPtr--; + + //optimize the push/pop + Statement action = (Statement) astStack[astPtr]; + if (action instanceof EmptyStatement + && problemReporter.options.complianceLevel <= CompilerOptions.JDK1_3) { + expressionLengthPtr--; + astStack[astPtr] = + new DoStatement( + expressionStack[expressionPtr--], + null, + intStack[intPtr--], + endPosition); + } else { + expressionLengthPtr--; + astStack[astPtr] = + new DoStatement( + expressionStack[expressionPtr--], + action, + intStack[intPtr--], + endPosition); + } +} +protected void consumeStatementExpressionList() { + // StatementExpressionList ::= StatementExpressionList ',' StatementExpression + concatExpressionLists(); +} +protected void consumeStatementFor() { + // ForStatement ::= 'for' '(' ForInitopt ';' Expressionopt ';' ForUpdateopt ')' Statement + // ForStatementNoShortIf ::= 'for' '(' ForInitopt ';' Expressionopt ';' ForUpdateopt ')' StatementNoShortIf + + int length; + Expression cond = null; + Statement[] inits, updates; + Statement action; + boolean scope = true; + + //statements + astLengthPtr--; // we need to consume it + action = (Statement) astStack[astPtr--]; + if (action instanceof EmptyStatement + && problemReporter.options.complianceLevel <= CompilerOptions.JDK1_3) { + action = null; + } + + //updates are on the expresion stack + if ((length = expressionLengthStack[expressionLengthPtr--]) == 0) { + updates = null; + } else { + expressionPtr -= length; + System.arraycopy( + expressionStack, + expressionPtr + 1, + updates = new Statement[length], + 0, + length); + } + + if (expressionLengthStack[expressionLengthPtr--] != 0) + cond = expressionStack[expressionPtr--]; + + //inits may be on two different stacks + if ((length = astLengthStack[astLengthPtr--]) == 0) { + inits = null; + scope = false; + } else { + if (length == -1) { //on expressionStack + scope = false; + length = expressionLengthStack[expressionLengthPtr--]; + expressionPtr -= length; + System.arraycopy( + expressionStack, + expressionPtr + 1, + inits = new Statement[length], + 0, + length); + } else { //on astStack + astPtr -= length; + System.arraycopy( + astStack, + astPtr + 1, + inits = new Statement[length], + 0, + length); + } + }; + if (action instanceof Block) { + pushOnAstStack( + new ForStatement( + inits, + cond, + updates, + action, + scope, + intStack[intPtr--], + endStatementPosition)); + } else { + pushOnAstStack( + new ForStatement( + inits, + cond, + updates, + action, + scope, + intStack[intPtr--], + endPosition)); + } +} +protected void consumeStatementIfNoElse() { + // IfThenStatement ::= 'if' '(' Expression ')' Statement + + //optimize the push/pop + expressionLengthPtr--; + Statement thenStatement = (Statement) astStack[astPtr]; + if (thenStatement instanceof Block) { + astStack[astPtr] = + new IfStatement( + expressionStack[expressionPtr--], + thenStatement, + intStack[intPtr--], + endStatementPosition); + } else if (thenStatement instanceof EmptyStatement) { + astStack[astPtr] = + new IfStatement( + expressionStack[expressionPtr--], + Block.None, + intStack[intPtr--], + endStatementPosition); + } else { + astStack[astPtr] = + new IfStatement( + expressionStack[expressionPtr--], + thenStatement, + intStack[intPtr--], + endStatementPosition); + } +} +protected void consumeStatementIfWithElse() { + // IfThenElseStatement ::= 'if' '(' Expression ')' StatementNoShortIf 'else' Statement + // IfThenElseStatementNoShortIf ::= 'if' '(' Expression ')' StatementNoShortIf 'else' StatementNoShortIf + + astLengthPtr--; // optimized {..., Then, Else } ==> {..., If } + expressionLengthPtr--; + //optimize the push/pop + Statement elseStatement = (Statement) astStack[astPtr--]; + Statement thenStatement = (Statement) astStack[astPtr]; + if (elseStatement instanceof EmptyStatement) { + elseStatement = Block.None; + } + if (thenStatement instanceof EmptyStatement) { + thenStatement = Block.None; + } + if (elseStatement instanceof Block) { + astStack[astPtr] = + new IfStatement( + expressionStack[expressionPtr--], + thenStatement, + elseStatement, + intStack[intPtr--], + endStatementPosition); + } else { + astStack[astPtr] = + new IfStatement( + expressionStack[expressionPtr--], + thenStatement, + elseStatement, + intStack[intPtr--], + endStatementPosition); + } +} +protected void consumeStatementLabel() { + // LabeledStatement ::= 'Identifier' ':' Statement + // LabeledStatementNoShortIf ::= 'Identifier' ':' StatementNoShortIf + + //optimize push/pop + + Statement stmt = (Statement) astStack[astPtr]; + if (stmt instanceof EmptyStatement) { + astStack[astPtr] = + new LabeledStatement( + identifierStack[identifierPtr], + Block.None, + (int) (identifierPositionStack[identifierPtr--] >>> 32), + endStatementPosition); + } else { + astStack[astPtr] = + new LabeledStatement( + identifierStack[identifierPtr], + stmt, + (int) (identifierPositionStack[identifierPtr--] >>> 32), + endStatementPosition); + } + identifierLengthPtr--; +} +protected void consumeStatementReturn() { + // ReturnStatement ::= 'return' Expressionopt ';' + // return pushs a position on intStack in case there is no expression + + if (expressionLengthStack[expressionLengthPtr--] != 0) { + pushOnAstStack( + new ReturnStatement( + expressionStack[expressionPtr--], + intStack[intPtr--], + endPosition) + ); + } else { + pushOnAstStack(new ReturnStatement(null, intStack[intPtr--], endPosition)); + } +} +protected void consumeStatementSwitch() { + // SwitchStatement ::= 'switch' OpenBlock '(' Expression ')' SwitchBlock + + //OpenBlock just makes the semantic action blockStart() + //the block is inlined but a scope need to be created + //if some declaration occurs. + + int length; + SwitchStatement s = new SwitchStatement(); + expressionLengthPtr--; + s.testExpression = expressionStack[expressionPtr--]; + if ((length = astLengthStack[astLengthPtr--]) != 0) { + astPtr -= length; + System.arraycopy( + astStack, + astPtr + 1, + s.statements = new Statement[length], + 0, + length); + } + s.explicitDeclarations = realBlockStack[realBlockPtr--]; + pushOnAstStack(s); + intPtr--; // because of OpenBlock + s.sourceStart = intStack[intPtr--]; + s.sourceEnd = endStatementPosition; +} +protected void consumeStatementSynchronized() { + // SynchronizedStatement ::= OnlySynchronized '(' Expression ')' Block + //optimize the push/pop + + if (astLengthStack[astLengthPtr] == 0) { + astLengthStack[astLengthPtr] = 1; + expressionLengthPtr--; + astStack[++astPtr] = + new SynchronizedStatement( + expressionStack[expressionPtr--], + Block.None, + intStack[intPtr--], + endStatementPosition); + } else { + expressionLengthPtr--; + astStack[astPtr] = + new SynchronizedStatement( + expressionStack[expressionPtr--], + (Block) astStack[astPtr], + intStack[intPtr--], + endStatementPosition); + } + resetModifiers(); +} +protected void consumeStatementThrow() { + // ThrowStatement ::= 'throw' Expression ';' + expressionLengthPtr--; + pushOnAstStack(new ThrowStatement(expressionStack[expressionPtr--], intStack[intPtr--])); +} +protected void consumeStatementTry(boolean withFinally) { + //TryStatement ::= 'try' Block Catches + //TryStatement ::= 'try' Block Catchesopt Finally + + int length; + TryStatement tryStmt = new TryStatement(); + //finally + if (withFinally) { + astLengthPtr--; + tryStmt.finallyBlock = (Block) astStack[astPtr--]; + } + //catches are handle by two [see statementCatch] + if ((length = astLengthStack[astLengthPtr--]) != 0) { + if (length == 1) { + tryStmt.catchBlocks = new Block[] {(Block) astStack[astPtr--]}; + tryStmt.catchArguments = new Argument[] {(Argument) astStack[astPtr--]}; + } else { + Block[] bks = (tryStmt.catchBlocks = new Block[length]); + Argument[] args = (tryStmt.catchArguments = new Argument[length]); + while (length-- > 0) { + bks[length] = (Block) astStack[astPtr--]; + args[length] = (Argument) astStack[astPtr--]; + } + } + } + //try + astLengthPtr--; + tryStmt.tryBlock = (Block) astStack[astPtr--]; + + //positions + tryStmt.sourceEnd = endStatementPosition; + tryStmt.sourceStart = intStack[intPtr--]; + pushOnAstStack(tryStmt); +} +protected void consumeStatementWhile() { + // WhileStatement ::= 'while' '(' Expression ')' Statement + // WhileStatementNoShortIf ::= 'while' '(' Expression ')' StatementNoShortIf + + Statement action = (Statement) astStack[astPtr]; + expressionLengthPtr--; + if (action instanceof Block) { + astStack[astPtr] = + new WhileStatement( + expressionStack[expressionPtr--], + action, + intStack[intPtr--], + endStatementPosition); + } else { + if (action instanceof EmptyStatement + && problemReporter.options.complianceLevel <= CompilerOptions.JDK1_3) { + astStack[astPtr] = + new WhileStatement( + expressionStack[expressionPtr--], + null, + intStack[intPtr--], + endPosition); + } else { + astStack[astPtr] = + new WhileStatement( + expressionStack[expressionPtr--], + action, + intStack[intPtr--], + endPosition); + } + } +} +protected void consumeStaticInitializer() { + // StaticInitializer ::= StaticOnly Block + //push an Initializer + //optimize the push/pop + Initializer initializer = new Initializer((Block) astStack[astPtr], AccStatic); + astStack[astPtr] = initializer; + initializer.sourceEnd = endStatementPosition; + initializer.declarationSourceEnd = flushAnnotationsDefinedPriorTo(endStatementPosition); + nestedMethod[nestedType] --; + initializer.declarationSourceStart = intStack[intPtr--]; + + // recovery + if (currentElement != null){ + lastCheckPoint = initializer.declarationSourceEnd; + currentElement = currentElement.add(initializer, 0); + lastIgnoredToken = -1; + } +} +protected void consumeStaticOnly() { + // StaticOnly ::= 'static' + int savedModifiersSourceStart = modifiersSourceStart; + checkAnnotation(); // might update declaration source start + if (modifiersSourceStart >= savedModifiersSourceStart) { + modifiersSourceStart = savedModifiersSourceStart; + } + pushOnIntStack( + modifiersSourceStart >= 0 ? modifiersSourceStart : scanner.startPosition); + jumpOverMethodBody(); + nestedMethod[nestedType]++; + resetModifiers(); + + // recovery + if (currentElement != null){ + recoveredStaticInitializerStart = intStack[intPtr]; // remember start position only for static initializers + } +} +protected void consumeSwitchBlock() { + // SwitchBlock ::= '{' SwitchBlockStatements SwitchLabels '}' + concatNodeLists(); +} +protected void consumeSwitchBlockStatement() { + // SwitchBlockStatement ::= SwitchLabels BlockStatements + concatNodeLists(); +} +protected void consumeSwitchBlockStatements() { + // SwitchBlockStatements ::= SwitchBlockStatements SwitchBlockStatement + concatNodeLists(); +} +protected void consumeSwitchLabels() { + // SwitchLabels ::= SwitchLabels SwitchLabel + optimizedConcatNodeLists(); +} +protected void consumeToken(int type) { + /* remember the last consumed value */ + /* try to minimize the number of build values */ + if (scanner.wasNonExternalizedStringLiteral) { + StringLiteral[] literals = this.scanner.nonNLSStrings; + // could not reproduce, but this is the only NPE + // added preventive null check see PR 9035 + if (literals != null) { + for (int i = 0, max = literals.length; i < max; i++) { + problemReporter().nonExternalizedStringLiteral(literals[i]); + } + } + scanner.currentLine = null; + scanner.wasNonExternalizedStringLiteral = false; + } + // clear the commentPtr of the scanner in case we read something different from a modifier + switch(type) { +// case TokenNameabstract : +// case TokenNamestrictfp : +// case TokenNamefinal : +// case TokenNamenative : +// case TokenNameprivate : +// case TokenNameprotected : +// case TokenNamepublic : +// case TokenNametransient : +// case TokenNamevolatile : + case TokenNamestatic : +// case TokenNamesynchronized : + break; + default: + scanner.commentPtr = -1; + } + //System.out.println(scanner.toStringAction(type)); + switch (type) { + case TokenNameIdentifier : + pushIdentifier(); + if (scanner.useAssertAsAnIndentifier) { + long positions = identifierPositionStack[identifierPtr]; + problemReporter().useAssertAsAnIdentifier((int) (positions >>> 32), (int) positions); + } + scanner.commentPtr = -1; + break; +// case TokenNameinterface : +// adjustInterfaceModifiers(); +// //'class' is pushing two int (positions) on the stack ==> 'interface' needs to do it too.... +// pushOnIntStack(scanner.startPosition); +// pushOnIntStack(scanner.currentPosition - 1); +// scanner.commentPtr = -1; +// break; +// case TokenNameabstract : +// checkAndSetModifiers(AccAbstract); +// break; +// case TokenNamestrictfp : +// checkAndSetModifiers(AccStrictfp); +// break; +// case TokenNamefinal : +// checkAndSetModifiers(AccFinal); +// break; +// case TokenNamenative : +// checkAndSetModifiers(AccNative); +// break; +// case TokenNameprivate : +// checkAndSetModifiers(AccPrivate); +// break; +// case TokenNameprotected : +// checkAndSetModifiers(AccProtected); +// break; +// case TokenNamepublic : +// checkAndSetModifiers(AccPublic); +// break; +// case TokenNametransient : +// checkAndSetModifiers(AccTransient); +// break; +// case TokenNamevolatile : +// checkAndSetModifiers(AccVolatile); +// break; + case TokenNamestatic : + checkAndSetModifiers(AccStatic); + break; +// case TokenNamesynchronized : +// this.synchronizedBlockSourceStart = scanner.startPosition; +// checkAndSetModifiers(AccSynchronized); +// break; +// //============================== +// case TokenNamevoid : +// pushIdentifier(-T_void); +// pushOnIntStack(scanner.currentPosition - 1); +// pushOnIntStack(scanner.startPosition); +// scanner.commentPtr = -1; +// break; +// //push a default dimension while void is not part of the primitive +// //declaration baseType and so takes the place of a type without getting into +// //regular type parsing that generates a dimension on intStack +// case TokenNameboolean : +// pushIdentifier(-T_boolean); +// pushOnIntStack(scanner.currentPosition - 1); +// pushOnIntStack(scanner.startPosition); +// scanner.commentPtr = -1; +// break; +// case TokenNamebyte : +// pushIdentifier(-T_byte); +// pushOnIntStack(scanner.currentPosition - 1); +// pushOnIntStack(scanner.startPosition); +// scanner.commentPtr = -1; +// break; +// case TokenNamechar : +// pushIdentifier(-T_char); +// pushOnIntStack(scanner.currentPosition - 1); +// pushOnIntStack(scanner.startPosition); +// scanner.commentPtr = -1; +// break; +// case TokenNamedouble : +// pushIdentifier(-T_double); +// pushOnIntStack(scanner.currentPosition - 1); +// pushOnIntStack(scanner.startPosition); +// scanner.commentPtr = -1; +// break; +// case TokenNamefloat : +// pushIdentifier(-T_float); +// pushOnIntStack(scanner.currentPosition - 1); +// pushOnIntStack(scanner.startPosition); +// scanner.commentPtr = -1; +// break; +// case TokenNameint : +// pushIdentifier(-T_int); +// pushOnIntStack(scanner.currentPosition - 1); +// pushOnIntStack(scanner.startPosition); +// scanner.commentPtr = -1; +// break; +// case TokenNamelong : +// pushIdentifier(-T_long); +// pushOnIntStack(scanner.currentPosition - 1); +// pushOnIntStack(scanner.startPosition); +// scanner.commentPtr = -1; +// break; +// case TokenNameshort : +// pushIdentifier(-T_short); +// pushOnIntStack(scanner.currentPosition - 1); +// pushOnIntStack(scanner.startPosition); +// scanner.commentPtr = -1; +// break; + //============================== + case TokenNameIntegerLiteral : + pushOnExpressionStack( + new IntLiteral( + scanner.getCurrentTokenSource(), + scanner.startPosition, + scanner.currentPosition - 1)); + scanner.commentPtr = -1; + break; + case TokenNameLongLiteral : + pushOnExpressionStack( + new LongLiteral( + scanner.getCurrentTokenSource(), + scanner.startPosition, + scanner.currentPosition - 1)); + scanner.commentPtr = -1; + break; + case TokenNameFloatingPointLiteral : + pushOnExpressionStack( + new FloatLiteral( + scanner.getCurrentTokenSource(), + scanner.startPosition, + scanner.currentPosition - 1)); + scanner.commentPtr = -1; + break; + case TokenNameDoubleLiteral : + pushOnExpressionStack( + new DoubleLiteral( + scanner.getCurrentTokenSource(), + scanner.startPosition, + scanner.currentPosition - 1)); + scanner.commentPtr = -1; + break; + case TokenNameCharacterLiteral : + pushOnExpressionStack( + new CharLiteral( + scanner.getCurrentTokenSource(), + scanner.startPosition, + scanner.currentPosition - 1)); + scanner.commentPtr = -1; + break; + case TokenNameStringLiteral : + StringLiteral stringLiteral = new StringLiteral( + scanner.getCurrentTokenSourceString(), + scanner.startPosition, + scanner.currentPosition - 1); + pushOnExpressionStack(stringLiteral); + scanner.commentPtr = -1; + break; + case TokenNamefalse : + pushOnExpressionStack( + new FalseLiteral(scanner.startPosition, scanner.currentPosition - 1)); + scanner.commentPtr = -1; + break; + case TokenNametrue : + pushOnExpressionStack( + new TrueLiteral(scanner.startPosition, scanner.currentPosition - 1)); + break; + case TokenNamenull : + pushOnExpressionStack( + new NullLiteral(scanner.startPosition, scanner.currentPosition - 1)); + break; + //============================ +// case TokenNamesuper : +// case TokenNamethis : +// endPosition = scanner.currentPosition - 1; +// pushOnIntStack(scanner.startPosition); +// break; +// case TokenNameassert : +// case TokenNameimport : +// case TokenNamepackage : +// case TokenNamethrow : + case TokenNamenew : + case TokenNamedo : + case TokenNameif : + case TokenNamefor : + case TokenNameswitch : +// case TokenNametry : + case TokenNamewhile : + case TokenNamebreak : + case TokenNamecontinue : + case TokenNamereturn : + case TokenNamecase : + pushOnIntStack(scanner.startPosition); + break; + case TokenNameclass : + pushOnIntStack(scanner.currentPosition - 1); + pushOnIntStack(scanner.startPosition); + break; + case TokenNamedefault : + pushOnIntStack(scanner.startPosition); + pushOnIntStack(scanner.currentPosition - 1); + break; + //let extra semantic action decide when to push + case TokenNameRBRACKET : + case TokenNamePLUS : + case TokenNameMINUS : + case TokenNameNOT : + case TokenNameTWIDDLE : + endPosition = scanner.startPosition; + break; + case TokenNamePLUS_PLUS : + case TokenNameMINUS_MINUS : + endPosition = scanner.startPosition; + endStatementPosition = scanner.currentPosition - 1; + break; + case TokenNameRBRACE: + case TokenNameSEMICOLON : + endStatementPosition = scanner.currentPosition - 1; + endPosition = scanner.startPosition - 1; + //the item is not part of the potential futur expression/statement + break; + // in order to handle ( expression) ////// (cast)expression///// foo(x) + case TokenNameRPAREN : + rParenPos = scanner.currentPosition - 1; // position of the end of right parenthesis (in case of unicode \u0029) lex00101 + break; + case TokenNameLPAREN : + lParenPos = scanner.startPosition; + break; + // case TokenNameQUESTION : + // case TokenNameCOMMA : + // case TokenNameCOLON : + // case TokenNameEQUAL : + // case TokenNameLBRACKET : + // case TokenNameDOT : + // case TokenNameERROR : + // case TokenNameEOF : + // case TokenNamecase : + // case TokenNamecatch : + // case TokenNameelse : + // case TokenNameextends : + // case TokenNamefinally : + // case TokenNameimplements : + // case TokenNamethrows : + // case TokenNameinstanceof : + // case TokenNameEQUAL_EQUAL : + // case TokenNameLESS_EQUAL : + // case TokenNameGREATER_EQUAL : + // case TokenNameNOT_EQUAL : + // case TokenNameLEFT_SHIFT : + // case TokenNameRIGHT_SHIFT : + // case TokenNameUNSIGNED_RIGHT_SHIFT : + // case TokenNamePLUS_EQUAL : + // case TokenNameMINUS_EQUAL : + // case TokenNameMULTIPLY_EQUAL : + // case TokenNameDIVIDE_EQUAL : + // case TokenNameAND_EQUAL : + // case TokenNameOR_EQUAL : + // case TokenNameXOR_EQUAL : + // case TokenNameREMAINDER_EQUAL : + // case TokenNameLEFT_SHIFT_EQUAL : + // case TokenNameRIGHT_SHIFT_EQUAL : + // case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : + // case TokenNameOR_OR : + // case TokenNameAND_AND : + // case TokenNameREMAINDER : + // case TokenNameXOR : + // case TokenNameAND : + // case TokenNameMULTIPLY : + // case TokenNameOR : + // case TokenNameDIVIDE : + // case TokenNameGREATER : + // case TokenNameLESS : + } +} +protected void consumeTypeDeclarations() { + // TypeDeclarations ::= TypeDeclarations TypeDeclaration + concatNodeLists(); +} +protected void consumeTypeDeclarationsopt() { + // TypeDeclarationsopt ::= TypeDeclarations + int length; + if ((length = astLengthStack[astLengthPtr--]) != 0) { + astPtr -= length; + System.arraycopy(astStack, astPtr + 1, compilationUnit.types = new TypeDeclaration[length], 0, length); + } +} +protected void consumeTypeImportOnDemandDeclaration() { + // TypeImportOnDemandDeclaration ::= TypeImportOnDemandDeclarationName ';' + + ImportReference impt = (ImportReference) astStack[astPtr]; + // flush annotations defined prior to import statements + impt.declarationEnd = endStatementPosition; + impt.declarationSourceEnd = + this.flushAnnotationsDefinedPriorTo(impt.declarationSourceEnd); + + // recovery + if (currentElement != null) { + lastCheckPoint = impt.declarationSourceEnd + 1; + currentElement = currentElement.add(impt, 0); + restartRecovery = true; + lastIgnoredToken = -1; + // used to avoid branching back into the regular automaton + } +} +protected void consumeTypeImportOnDemandDeclarationName() { + // TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*' + /* push an ImportRef build from the last name + stored in the identifier stack. */ + + ImportReference impt; + int length; + char[][] tokens = new char[length = identifierLengthStack[identifierLengthPtr--]][]; + identifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length); + System.arraycopy(identifierPositionStack, identifierPtr + 1, positions, 0, length); + pushOnAstStack(impt = new ImportReference(tokens, positions, true)); + + if (currentToken == TokenNameSEMICOLON){ + impt.declarationSourceEnd = scanner.currentPosition - 1; + } else { + impt.declarationSourceEnd = impt.sourceEnd; + } + impt.declarationEnd = impt.declarationSourceEnd; + //endPosition is just before the ; + impt.declarationSourceStart = intStack[intPtr--]; + + // recovery + if (currentElement != null){ + lastCheckPoint = impt.declarationSourceEnd+1; + currentElement = currentElement.add(impt, 0); + lastIgnoredToken = -1; + restartRecovery = true; // used to avoid branching back into the regular automaton + } +} +protected void consumeUnaryExpression(int op) { + // UnaryExpression ::= '+' PushPosition UnaryExpression + // UnaryExpression ::= '-' PushPosition UnaryExpression + // UnaryExpressionNotPlusMinus ::= '~' PushPosition UnaryExpression + // UnaryExpressionNotPlusMinus ::= '!' PushPosition UnaryExpression + + //optimize the push/pop + + //handle manually the -2147483648 while it is not a real + //computation of an - and 2147483648 (notice that 2147483648 + //is Integer.MAX_VALUE+1.....) + //Same for -9223372036854775808L ............ + + //intStack have the position of the operator + + Expression r, exp = expressionStack[expressionPtr]; + if (op == MINUS) { + if ((exp instanceof IntLiteral) && (((IntLiteral) exp).mayRepresentMIN_VALUE())) { + r = expressionStack[expressionPtr] = new IntLiteralMinValue(); + } else { + if ((exp instanceof LongLiteral) && (((LongLiteral) exp).mayRepresentMIN_VALUE())) { + r = expressionStack[expressionPtr] = new LongLiteralMinValue(); + } else { + r = expressionStack[expressionPtr] = new UnaryExpression(exp, op); + } + } + } else { + r = expressionStack[expressionPtr] = new UnaryExpression(exp, op); + } + r.sourceStart = intStack[intPtr--]; + r.sourceEnd = exp.sourceEnd; +} +protected void consumeUnaryExpression(int op, boolean post) { + // PreIncrementExpression ::= '++' PushPosition UnaryExpression + // PreDecrementExpression ::= '--' PushPosition UnaryExpression + + // ++ and -- operators + //optimize the push/pop + + //intStack has the position of the operator when prefix + + Expression leftHandSide = expressionStack[expressionPtr]; + if (leftHandSide instanceof Reference) { + // ++foo()++ is unvalid + if (post) { + expressionStack[expressionPtr] = + new PostfixExpression( + leftHandSide, + IntLiteral.One, + op, + endStatementPosition); + } else { + expressionStack[expressionPtr] = + new PrefixExpression( + leftHandSide, + IntLiteral.One, + op, + intStack[intPtr--]); + } + } else { + //the ++ or the -- is NOT taken into account if code gen proceeds + if (!post) { + intPtr--; + } + problemReporter().invalidUnaryExpression(leftHandSide); + } +} +protected void consumeVariableDeclarators() { + // VariableDeclarators ::= VariableDeclarators ',' VariableDeclarator + optimizedConcatNodeLists(); +} +protected void consumeVariableInitializers() { + // VariableInitializers ::= VariableInitializers ',' VariableInitializer + concatExpressionLists(); +} +protected TypeReference copyDims(TypeReference typeRef, int dim) { + return typeRef.copyDims(dim); +} +protected FieldDeclaration createFieldDeclaration(Expression initialization, char[] name, int sourceStart, int sourceEnd) { + return new FieldDeclaration(null, name, sourceStart, sourceEnd); +} + +protected LocalDeclaration createLocalDeclaration(Expression initialization, char[] name, int sourceStart, int sourceEnd) { + return new LocalDeclaration(null, name, sourceStart, sourceEnd); +} + +public CompilationUnitDeclaration dietParse(ICompilationUnit sourceUnit, CompilationResult compilationResult) { + + CompilationUnitDeclaration parsedUnit; + boolean old = diet; + try { + diet = true; + parsedUnit = parse(sourceUnit, compilationResult); + } + finally { + diet = old; + } + return parsedUnit; +} +protected void dispatchDeclarationInto(int length) { + /* they are length on astStack that should go into + methods fields constructors lists of the typeDecl + + Return if there is a constructor declaration in the methods declaration */ + + + // Looks for the size of each array . + + if (length == 0) + return; + int[] flag = new int[length + 1]; //plus one -- see + int size1 = 0, size2 = 0, size3 = 0; + for (int i = length - 1; i >= 0; i--) { + AstNode astNode = astStack[astPtr--]; + if (astNode instanceof AbstractMethodDeclaration) { + //methods and constructors have been regrouped into one single list + flag[i] = 3; + size2++; + } else { + if (astNode instanceof TypeDeclaration) { + flag[i] = 4; + size3++; + } else { + //field + flag[i] = 1; + size1++; + } + } + } + + //arrays creation + TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr]; + if (size1 != 0) + typeDecl.fields = new FieldDeclaration[size1]; + if (size2 != 0) + typeDecl.methods = new AbstractMethodDeclaration[size2]; + if (size3 != 0) + typeDecl.memberTypes = new MemberTypeDeclaration[size3]; + + //arrays fill up + size1 = size2 = size3 = 0; + int flagI = flag[0], start = 0; + int length2; + for (int end = 0; end <= length; end++) // the plus one allows to + { + if (flagI != flag[end]) //treat the last element as a ended flag..... + { //array copy + switch (flagI) { + case 1 : + size1 += (length2 = end - start); + System.arraycopy( + astStack, + astPtr + start + 1, + typeDecl.fields, + size1 - length2, + length2); + break; + case 3 : + size2 += (length2 = end - start); + System.arraycopy( + astStack, + astPtr + start + 1, + typeDecl.methods, + size2 - length2, + length2); + break; + case 4 : + size3 += (length2 = end - start); + System.arraycopy( + astStack, + astPtr + start + 1, + typeDecl.memberTypes, + size3 - length2, + length2); + break; + }; + flagI = flag[start = end]; + } + } + + if (typeDecl.memberTypes != null) { + for (int i = typeDecl.memberTypes.length - 1; i >= 0; i--) { + typeDecl.memberTypes[i].enclosingType = typeDecl; + } + } +} +protected CompilationUnitDeclaration endParse(int act) { + + this.lastAct = act; + + if (currentElement != null){ + currentElement.topElement().updateParseTree(); + if (VERBOSE_RECOVERY){ + System.out.print(Util.bind("parser.syntaxRecovery")); //$NON-NLS-1$ + System.out.println("--------------------------"); //$NON-NLS-1$ + System.out.println(compilationUnit); + System.out.println("----------------------------------"); //$NON-NLS-1$ + } + } else { + if (diet & VERBOSE_RECOVERY){ + System.out.print(Util.bind("parser.regularParse")); //$NON-NLS-1$ + System.out.println("--------------------------"); //$NON-NLS-1$ + System.out.println(compilationUnit); + System.out.println("----------------------------------"); //$NON-NLS-1$ + } + } + if (scanner.recordLineSeparator) { + compilationUnit.compilationResult.lineSeparatorPositions = scanner.getLineEnds(); + } + return compilationUnit; +} +/* + * Flush annotations defined prior to a given positions. + * + * Note: annotations are stacked in syntactical order + * + * Either answer given , or the end position of a comment line + * immediately following the (same line) + * + * e.g. + * void foo(){ + * } // end of method foo + */ + +public int flushAnnotationsDefinedPriorTo(int position) { + + int lastAnnotationIndex = scanner.commentPtr; + if (lastAnnotationIndex < 0) return position; // no comment + + // compute the index of the first obsolete comment + int index = lastAnnotationIndex; + int validCount = 0; + while (index >= 0){ + int commentEnd = scanner.commentStops[index]; + if (commentEnd < 0) commentEnd = -commentEnd; // negative end position for non-javadoc comments + if (commentEnd <= position){ + break; + } + index--; + validCount++; + } + // if the source at is immediately followed by a line comment, then + // flush this comment and shift to the comment end. + if (validCount > 0){ + int immediateCommentEnd = -scanner.commentStops[index+1]; //non-javadoc comment end positions are negative + if (immediateCommentEnd > 0){ // only tolerating non-javadoc comments + // is there any line break until the end of the immediate comment ? (thus only tolerating line comment) + immediateCommentEnd--; // comment end in one char too far + if (scanner.getLineNumber(position) == scanner.getLineNumber(immediateCommentEnd)){ + position = immediateCommentEnd; + validCount--; // flush this comment + index++; + } + } + } + // position can be located in the middle of a line break + // this is a bug on Windows platform only. + // http://dev.eclipse.org/bugs/show_bug.cgi?id=10557 + char[] source = scanner.source; + + if ((position < source.length) + && (source[position] == '\r') + && ((position + 1) < source.length) + && (source[position + 1] == '\n')) { + position++; + } + if (index < 0) return position; // no obsolete comment + + if (validCount > 0){ // move valid comment infos, overriding obsolete comment infos + System.arraycopy(scanner.commentStarts, index + 1, scanner.commentStarts, 0, validCount); + System.arraycopy(scanner.commentStops, index + 1, scanner.commentStops, 0, validCount); + } + scanner.commentPtr = validCount - 1; + return position; +} +public final int getFirstToken() { + // the first token is a virtual token that + // allows the parser to parse several goals + // even if they aren't LALR(1).... + // Goal ::= '++' CompilationUnit + // Goal ::= '--' MethodBody + // Goal ::= '==' ConstructorBody + // -- Initializer + // Goal ::= '>>' StaticInitializer + // Goal ::= '>>' Block + // -- error recovery + // Goal ::= '>>>' Headers + // Goal ::= '*' BlockStatements + // Goal ::= '*' MethodPushModifiersHeader + // -- JDOM + // Goal ::= '&&' FieldDeclaration + // Goal ::= '||' ImportDeclaration + // Goal ::= '?' PackageDeclaration + // Goal ::= '+' TypeDeclaration + // Goal ::= '/' GenericMethodDeclaration + // Goal ::= '&' ClassBodyDeclaration + // -- code snippet + // Goal ::= '%' Expression + // -- completion parser + // Goal ::= '!' ConstructorBlockStatementsopt + // Goal ::= '~' BlockStatementsopt + + return firstToken; +} +/* + * Answer back an array of sourceStart/sourceEnd positions of the available JavaDoc comments. + * The array is a flattened structure: 2*n entries with consecutives start and end positions. + * + * If no JavaDoc is available, then null is answered instead of an empty array. + * + * e.g. { 10, 20, 25, 45 } --> javadoc1 from 10 to 20, javadoc2 from 25 to 45 + */ +public int[] getJavaDocPositions() { + + int javadocCount = 0; + for (int i = 0, max = scanner.commentPtr; i <= max; i++){ + // javadoc only (non javadoc comment have negative end positions.) + if (scanner.commentStops[i] > 0){ + javadocCount++; + } + } + if (javadocCount == 0) return null; + + int[] positions = new int[2*javadocCount]; + int index = 0; + for (int i = 0, max = scanner.commentPtr; i <= max; i++){ + // javadoc only (non javadoc comment have negative end positions.) + if (scanner.commentStops[i] > 0){ + positions[index++] = scanner.commentStarts[i]; + positions[index++] = scanner.commentStops[i]-1; //stop is one over + } + } + return positions; +} + protected void getMethodBodies(CompilationUnitDeclaration unit) { + //fill the methods bodies in order for the code to be generated + + if (unit == null) return; + + if (unit.ignoreMethodBodies) { + unit.ignoreFurtherInvestigation = true; + return; + // if initial diet parse did not work, no need to dig into method bodies. + } + + //real parse of the method.... + this.scanner.setSource( + unit.compilationResult.compilationUnit.getContents()); + if (unit.types != null) { + for (int i = unit.types.length; --i >= 0;) + unit.types[i].parseMethod(this, unit); + } + } +protected TypeReference getTypeReference(int dim) { /* build a Reference on a variable that may be qualified or not +This variable is a type reference and dim will be its dimensions*/ + + int length; + TypeReference ref; + if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) { + // single variable reference + if (dim == 0) { + ref = + new SingleTypeReference( + identifierStack[identifierPtr], + identifierPositionStack[identifierPtr--]); + } else { + ref = + new ArrayTypeReference( + identifierStack[identifierPtr], + dim, + identifierPositionStack[identifierPtr--]); + ref.sourceEnd = endPosition; + } + } else { + if (length < 0) { //flag for precompiled type reference on base types + ref = TypeReference.baseTypeReference(-length, dim); + ref.sourceStart = intStack[intPtr--]; + if (dim == 0) { + ref.sourceEnd = intStack[intPtr--]; + } else { + intPtr--; + ref.sourceEnd = endPosition; + } + } else { //Qualified variable reference + char[][] tokens = new char[length][]; + identifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length); + System.arraycopy( + identifierPositionStack, + identifierPtr + 1, + positions, + 0, + length); + if (dim == 0) { + ref = new QualifiedTypeReference(tokens, positions); + } else { + ref = new ArrayQualifiedTypeReference(tokens, dim, positions); + ref.sourceEnd = endPosition; + } + } + }; + return ref; +} +protected Expression getTypeReference(Expression exp) { + + exp.bits &= ~AstNode.RestrictiveFlagMASK; + exp.bits |= TYPE; + return exp; +} +protected NameReference getUnspecifiedReference() { + /* build a (unspecified) NameReference which may be qualified*/ + + int length; + NameReference ref; + if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) + // single variable reference + ref = + new SingleNameReference( + identifierStack[identifierPtr], + identifierPositionStack[identifierPtr--]); + else + //Qualified variable reference + { + char[][] tokens = new char[length][]; + identifierPtr -= length; + System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length); + ref = + new QualifiedNameReference(tokens, + (int) (identifierPositionStack[identifierPtr + 1] >> 32), // sourceStart + (int) identifierPositionStack[identifierPtr + length]); // sourceEnd + }; + return ref; +} +protected NameReference getUnspecifiedReferenceOptimized() { + /* build a (unspecified) NameReference which may be qualified + The optimization occurs for qualified reference while we are + certain in this case the last item of the qualified name is + a field access. This optimization is IMPORTANT while it results + that when a NameReference is build, the type checker should always + look for that it is not a type reference */ + + int length; + NameReference ref; + if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) { + // single variable reference + ref = + new SingleNameReference( + identifierStack[identifierPtr], + identifierPositionStack[identifierPtr--]); + ref.bits &= ~AstNode.RestrictiveFlagMASK; + ref.bits |= LOCAL | FIELD; + return ref; + } + + //Qualified-variable-reference + //In fact it is variable-reference DOT field-ref , but it would result in a type + //conflict tha can be only reduce by making a superclass (or inetrface ) between + //nameReference and FiledReference or putting FieldReference under NameReference + //or else..........This optimisation is not really relevant so just leave as it is + + char[][] tokens = new char[length][]; + identifierPtr -= length; + System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length); + ref = new QualifiedNameReference( + tokens, + (int) (identifierPositionStack[identifierPtr + 1] >> 32), // sourceStart + (int) identifierPositionStack[identifierPtr + length]); // sourceEnd + ref.bits &= ~AstNode.RestrictiveFlagMASK; + ref.bits |= LOCAL | FIELD; + return ref; +} +public void goForBlockStatementsOrMethodHeaders() { + //tells the scanner to go for block statements or method headers parsing + + firstToken = TokenNameMULTIPLY; + scanner.recordLineSeparator = false; +} +public void goForClassBodyDeclarations() { + //tells the scanner to go for any body declarations parsing + + firstToken = TokenNameAND; + scanner.recordLineSeparator = true; +} +public void goForCompilationUnit(){ + //tells the scanner to go for compilation unit parsing + + firstToken = TokenNamePLUS_PLUS ; + scanner.linePtr = -1; + scanner.recordLineSeparator = true; + scanner.currentLine= null; + scanner.lines= new ArrayList(); +} +public void goForConstructorBody(){ + //tells the scanner to go for compilation unit parsing + + firstToken = TokenNameEQUAL_EQUAL ; + scanner.recordLineSeparator = false; +} +public void goForExpression() { + //tells the scanner to go for an expression parsing + + firstToken = TokenNameREMAINDER; + scanner.recordLineSeparator = false; +} +public void goForFieldDeclaration(){ + //tells the scanner to go for field declaration parsing + + firstToken = TokenNameAND_AND ; + scanner.recordLineSeparator = true; +} +public void goForGenericMethodDeclaration(){ + //tells the scanner to go for generic method declarations parsing + + firstToken = TokenNameDIVIDE; + scanner.recordLineSeparator = true; +} +public void goForHeaders(){ + //tells the scanner to go for headers only parsing + + firstToken = TokenNameUNSIGNED_RIGHT_SHIFT; + scanner.recordLineSeparator = true; +} +public void goForImportDeclaration(){ + //tells the scanner to go for import declaration parsing + + firstToken = TokenNameOR_OR ; + scanner.recordLineSeparator = true; +} +public void goForInitializer(){ + //tells the scanner to go for initializer parsing + + firstToken = TokenNameRIGHT_SHIFT ; + scanner.recordLineSeparator = false; +} +public void goForMethodBody(){ + //tells the scanner to go for method body parsing + + firstToken = TokenNameMINUS_MINUS ; + scanner.recordLineSeparator = false; +} +public void goForPackageDeclaration() { + //tells the scanner to go for package declaration parsing + + firstToken = TokenNameQUESTION; + scanner.recordLineSeparator = true; +} +public void goForTypeDeclaration() { + //tells the scanner to go for type (interface or class) declaration parsing + + firstToken = TokenNamePLUS; + scanner.recordLineSeparator = true; +} +public final static void grammar(){ +/* +--main options +%options ACTION, AN=JavaAction.java, GP=java, +%options FILE-PREFIX=java, ESCAPE=$, PREFIX=TokenName, OUTPUT-SIZE=125 , +%options NOGOTO-DEFAULT, SINGLE-PRODUCTIONS, LALR=1 , TABLE=TIME , + +--error recovering options..... +%options ERROR_MAPS + +--grammar understanding options +%options first follow +%options TRACE=FULL , +%options VERBOSE + +--Usefull macros helping reading/writing semantic actions +$Define +$putCase +/. case $rule_number : // System.out.println("$rule_text"); + ./ + +$break +/. + break ; +./ + +-- here it starts really ------------------------------------------ +$Terminals + + Identifier + + abstract assert boolean break byte case catch char class + continue default do double else extends false final finally float + for if implements import instanceof int + interface long native new null package private + protected public return short static strictfp super switch + synchronized this throw throws transient true try void + volatile while + + IntegerLiteral + LongLiteral + FloatingPointLiteral + DoubleLiteral + CharacterLiteral + StringLiteral + + PLUS_PLUS + MINUS_MINUS + EQUAL_EQUAL + LESS_EQUAL + GREATER_EQUAL + NOT_EQUAL + LEFT_SHIFT + RIGHT_SHIFT + UNSIGNED_RIGHT_SHIFT + PLUS_EQUAL + MINUS_EQUAL + MULTIPLY_EQUAL + DIVIDE_EQUAL + AND_EQUAL + OR_EQUAL + XOR_EQUAL + REMAINDER_EQUAL + LEFT_SHIFT_EQUAL + RIGHT_SHIFT_EQUAL + UNSIGNED_RIGHT_SHIFT_EQUAL + OR_OR + AND_AND + PLUS + MINUS + NOT + REMAINDER + XOR + AND + MULTIPLY + OR + TWIDDLE + DIVIDE + GREATER + LESS + LPAREN + RPAREN + LBRACE + RBRACE + LBRACKET + RBRACKET + SEMICOLON + QUESTION + COLON + COMMA + DOT + EQUAL + +-- BodyMarker + +$Alias + + '++' ::= PLUS_PLUS + '--' ::= MINUS_MINUS + '==' ::= EQUAL_EQUAL + '<=' ::= LESS_EQUAL + '>=' ::= GREATER_EQUAL + '!=' ::= NOT_EQUAL + '<<' ::= LEFT_SHIFT + '>>' ::= RIGHT_SHIFT + '>>>' ::= UNSIGNED_RIGHT_SHIFT + '+=' ::= PLUS_EQUAL + '-=' ::= MINUS_EQUAL + '*=' ::= MULTIPLY_EQUAL + '/=' ::= DIVIDE_EQUAL + '&=' ::= AND_EQUAL + '|=' ::= OR_EQUAL + '^=' ::= XOR_EQUAL + '%=' ::= REMAINDER_EQUAL + '<<=' ::= LEFT_SHIFT_EQUAL + '>>=' ::= RIGHT_SHIFT_EQUAL + '>>>=' ::= UNSIGNED_RIGHT_SHIFT_EQUAL + '||' ::= OR_OR + '&&' ::= AND_AND + + '+' ::= PLUS + '-' ::= MINUS + '!' ::= NOT + '%' ::= REMAINDER + '^' ::= XOR + '&' ::= AND + '*' ::= MULTIPLY + '|' ::= OR + '~' ::= TWIDDLE + '/' ::= DIVIDE + '>' ::= GREATER + '<' ::= LESS + '(' ::= LPAREN + ')' ::= RPAREN + '{' ::= LBRACE + '}' ::= RBRACE + '[' ::= LBRACKET + ']' ::= RBRACKET + ';' ::= SEMICOLON + '?' ::= QUESTION + ':' ::= COLON + ',' ::= COMMA + '.' ::= DOT + '=' ::= EQUAL + +$Start + Goal + +$Rules + +/. // This method is part of an automatic generation : do NOT edit-modify +protected void consumeRule(int act) { + switch ( act ) { +./ + + + +Goal ::= '++' CompilationUnit +Goal ::= '--' MethodBody +Goal ::= '==' ConstructorBody +-- Initializer +Goal ::= '>>' StaticInitializer +Goal ::= '>>' Initializer +-- error recovery +Goal ::= '>>>' Headers +Goal ::= '*' BlockStatements +Goal ::= '*' MethodPushModifiersHeader +Goal ::= '*' CatchHeader +-- JDOM +Goal ::= '&&' FieldDeclaration +Goal ::= '||' ImportDeclaration +Goal ::= '?' PackageDeclaration +Goal ::= '+' TypeDeclaration +Goal ::= '/' GenericMethodDeclaration +Goal ::= '&' ClassBodyDeclaration +-- code snippet +Goal ::= '%' Expression +-- completion parser +Goal ::= '!' ConstructorBlockStatementsopt +Goal ::= '~' BlockStatementsopt + +Literal -> IntegerLiteral +Literal -> LongLiteral +Literal -> FloatingPointLiteral +Literal -> DoubleLiteral +Literal -> CharacterLiteral +Literal -> StringLiteral +Literal -> null +Literal -> BooleanLiteral +BooleanLiteral -> true +BooleanLiteral -> false + +------------------------------------------------------------- +------------------------------------------------------------- +--a Type results in both a push of its dimension(s) and its name(s). + +Type ::= PrimitiveType + /.$putCase consumePrimitiveType(); $break ./ +Type -> ReferenceType + +PrimitiveType -> NumericType +NumericType -> IntegralType +NumericType -> FloatingPointType + +PrimitiveType -> 'boolean' +PrimitiveType -> 'void' +IntegralType -> 'byte' +IntegralType -> 'short' +IntegralType -> 'int' +IntegralType -> 'long' +IntegralType -> 'char' +FloatingPointType -> 'float' +FloatingPointType -> 'double' + +ReferenceType ::= ClassOrInterfaceType +/.$putCase consumeReferenceType(); $break ./ +ReferenceType -> ArrayType -- here a push of dimensions is done, that explains the two previous push 0 + +ClassOrInterfaceType -> Name + +-- +-- These rules have been rewritten to avoid some conflicts introduced +-- by adding the 1.1 features +-- +-- ArrayType ::= PrimitiveType '[' ']' +-- ArrayType ::= Name '[' ']' +-- ArrayType ::= ArrayType '[' ']' +-- + +ArrayType ::= PrimitiveType Dims +ArrayType ::= Name Dims + +ClassType -> ClassOrInterfaceType + + +-------------------------------------------------------------- +-------------------------------------------------------------- + +Name -> SimpleName +Name -> QualifiedName + +SimpleName -> 'Identifier' + +QualifiedName ::= Name '.' SimpleName +/.$putCase consumeQualifiedName(); $break ./ + +CompilationUnit ::= EnterCompilationUnit PackageDeclarationopt ImportDeclarationsopt TypeDeclarationsopt +/.$putCase consumeCompilationUnit(); $break ./ + +EnterCompilationUnit ::= $empty +/.$putCase consumeEnterCompilationUnit(); $break ./ + +Headers -> Header +Headers ::= Headers Header + +Header -> ImportDeclaration +Header -> PackageDeclaration +Header -> ClassHeader +Header -> InterfaceHeader +Header -> StaticInitializer +Header -> MethodHeader +Header -> ConstructorHeader +Header -> FieldDeclaration +Header -> AllocationHeader + +CatchHeader ::= 'catch' '(' FormalParameter ')' '{' +/.$putCase consumeCatchHeader(); $break ./ + +ImportDeclarations -> ImportDeclaration +ImportDeclarations ::= ImportDeclarations ImportDeclaration +/.$putCase consumeImportDeclarations(); $break ./ + +TypeDeclarations -> TypeDeclaration +TypeDeclarations ::= TypeDeclarations TypeDeclaration +/.$putCase consumeTypeDeclarations(); $break ./ + +PackageDeclaration ::= PackageDeclarationName ';' +/.$putCase consumePackageDeclaration(); $break ./ + +PackageDeclarationName ::= 'package' Name +/.$putCase consumePackageDeclarationName(); $break ./ + +ImportDeclaration -> SingleTypeImportDeclaration +ImportDeclaration -> TypeImportOnDemandDeclaration + +SingleTypeImportDeclaration ::= SingleTypeImportDeclarationName ';' +/.$putCase consumeSingleTypeImportDeclaration(); $break ./ + +SingleTypeImportDeclarationName ::= 'import' Name +/.$putCase consumeSingleTypeImportDeclarationName(); $break ./ + +TypeImportOnDemandDeclaration ::= TypeImportOnDemandDeclarationName ';' +/.$putCase consumeTypeImportOnDemandDeclaration(); $break ./ + +TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*' +/.$putCase consumeTypeImportOnDemandDeclarationName(); $break ./ + +TypeDeclaration -> ClassDeclaration +TypeDeclaration -> InterfaceDeclaration +-- this declaration in part of a list od declaration and we will +-- use and optimized list length calculation process +-- thus we decrement the number while it will be incremend..... +TypeDeclaration ::= ';' +/. $putCase consumeEmptyTypeDeclaration(); $break ./ + +--18.7 Only in the LALR(1) Grammar + +Modifiers ::= Modifier +Modifiers ::= Modifiers Modifier + +Modifier -> 'public' +Modifier -> 'protected' +Modifier -> 'private' +Modifier -> 'static' +Modifier -> 'abstract' +Modifier -> 'final' +Modifier -> 'native' +Modifier -> 'synchronized' +Modifier -> 'transient' +Modifier -> 'volatile' +Modifier -> 'strictfp' + +--18.8 Productions from 8: Class Declarations +--ClassModifier ::= +-- 'abstract' +-- | 'final' +-- | 'public' +--18.8.1 Productions from 8.1: Class Declarations + +ClassDeclaration ::= ClassHeader ClassBody +/.$putCase consumeClassDeclaration(); $break ./ + +ClassHeader ::= ClassHeaderName ClassHeaderExtendsopt ClassHeaderImplementsopt +/.$putCase consumeClassHeader(); $break ./ + +ClassHeaderName ::= Modifiersopt 'class' 'Identifier' +/.$putCase consumeClassHeaderName(); $break ./ + +ClassHeaderExtends ::= 'extends' ClassType +/.$putCase consumeClassHeaderExtends(); $break ./ + +ClassHeaderImplements ::= 'implements' InterfaceTypeList +/.$putCase consumeClassHeaderImplements(); $break ./ + +InterfaceTypeList -> InterfaceType +InterfaceTypeList ::= InterfaceTypeList ',' InterfaceType +/.$putCase consumeInterfaceTypeList(); $break ./ + +InterfaceType ::= ClassOrInterfaceType +/.$putCase consumeInterfaceType(); $break ./ + +ClassBody ::= '{' ClassBodyDeclarationsopt '}' + +ClassBodyDeclarations ::= ClassBodyDeclaration +ClassBodyDeclarations ::= ClassBodyDeclarations ClassBodyDeclaration +/.$putCase consumeClassBodyDeclarations(); $break ./ + +ClassBodyDeclaration -> ClassMemberDeclaration +ClassBodyDeclaration -> StaticInitializer +ClassBodyDeclaration -> ConstructorDeclaration +--1.1 feature +ClassBodyDeclaration ::= Diet NestedMethod Block +/.$putCase consumeClassBodyDeclaration(); $break ./ +Diet ::= $empty +/.$putCase consumeDiet(); $break./ + +Initializer ::= Diet NestedMethod Block +/.$putCase consumeClassBodyDeclaration(); $break ./ + +ClassMemberDeclaration -> FieldDeclaration +ClassMemberDeclaration -> MethodDeclaration +--1.1 feature +ClassMemberDeclaration -> ClassDeclaration +--1.1 feature +ClassMemberDeclaration -> InterfaceDeclaration + +-- Empty declarations are not valid Java ClassMemberDeclarations. +-- However, since the current (2/14/97) Java compiler accepts them +-- (in fact, some of the official tests contain this erroneous +-- syntax) + +GenericMethodDeclaration -> MethodDeclaration +GenericMethodDeclaration -> ConstructorDeclaration + +ClassMemberDeclaration ::= ';' +/.$putCase consumeEmptyClassMemberDeclaration(); $break./ + +--18.8.2 Productions from 8.3: Field Declarations +--VariableModifier ::= +-- 'public' +-- | 'protected' +-- | 'private' +-- | 'static' +-- | 'final' +-- | 'transient' +-- | 'volatile' + +FieldDeclaration ::= Modifiersopt Type VariableDeclarators ';' +/.$putCase consumeFieldDeclaration(); $break ./ + +VariableDeclarators -> VariableDeclarator +VariableDeclarators ::= VariableDeclarators ',' VariableDeclarator +/.$putCase consumeVariableDeclarators(); $break ./ + +VariableDeclarator ::= VariableDeclaratorId EnterVariable ExitVariableWithoutInitialization + +VariableDeclarator ::= VariableDeclaratorId EnterVariable '=' ForceNoDiet VariableInitializer RestoreDiet ExitVariableWithInitialization + +EnterVariable ::= $empty +/.$putCase consumeEnterVariable(); $break ./ + +ExitVariableWithInitialization ::= $empty +/.$putCase consumeExitVariableWithInitialization(); $break ./ + +ExitVariableWithoutInitialization ::= $empty +/.$putCase consumeExitVariableWithoutInitialization(); $break ./ + +ForceNoDiet ::= $empty +/.$putCase consumeForceNoDiet(); $break ./ +RestoreDiet ::= $empty +/.$putCase consumeRestoreDiet(); $break ./ + +VariableDeclaratorId ::= 'Identifier' Dimsopt + +VariableInitializer -> Expression +VariableInitializer -> ArrayInitializer + +--18.8.3 Productions from 8.4: Method Declarations +--MethodModifier ::= +-- 'public' +-- | 'protected' +-- | 'private' +-- | 'static' +-- | 'abstract' +-- | 'final' +-- | 'native' +-- | 'synchronized' +-- + +MethodDeclaration -> AbstractMethodDeclaration +MethodDeclaration ::= MethodHeader MethodBody +/.$putCase // set to true to consume a method with a body + consumeMethodDeclaration(true); $break ./ + +AbstractMethodDeclaration ::= MethodHeader ';' +/.$putCase // set to false to consume a method without body + consumeMethodDeclaration(false); $break ./ + +MethodHeader ::= MethodHeaderName MethodHeaderParameters MethodHeaderExtendedDims MethodHeaderThrowsClauseopt +/.$putCase consumeMethodHeader(); $break ./ + +MethodPushModifiersHeader ::= MethodPushModifiersHeaderName MethodHeaderParameters MethodHeaderExtendedDims MethodHeaderThrowsClauseopt +/.$putCase consumeMethodHeader(); $break ./ + +MethodPushModifiersHeaderName ::= Modifiers Type PushModifiers 'Identifier' '(' +/.$putCase consumeMethodPushModifiersHeaderName(); $break ./ + +MethodPushModifiersHeaderName ::= Type PushModifiers 'Identifier' '(' +/.$putCase consumeMethodPushModifiersHeaderName(); $break ./ + +MethodHeaderName ::= Modifiersopt Type 'Identifier' '(' +/.$putCase consumeMethodHeaderName(); $break ./ + +MethodHeaderParameters ::= FormalParameterListopt ')' +/.$putCase consumeMethodHeaderParameters(); $break ./ + +MethodHeaderExtendedDims ::= Dimsopt +/.$putCase consumeMethodHeaderExtendedDims(); $break ./ + +MethodHeaderThrowsClause ::= 'throws' ClassTypeList +/.$putCase consumeMethodHeaderThrowsClause(); $break ./ + +ConstructorHeader ::= ConstructorHeaderName MethodHeaderParameters MethodHeaderThrowsClauseopt +/.$putCase consumeConstructorHeader(); $break ./ + +ConstructorHeaderName ::= Modifiersopt 'Identifier' '(' +/.$putCase consumeConstructorHeaderName(); $break ./ + +FormalParameterList -> FormalParameter +FormalParameterList ::= FormalParameterList ',' FormalParameter +/.$putCase consumeFormalParameterList(); $break ./ + +--1.1 feature +FormalParameter ::= Modifiersopt Type VariableDeclaratorId +/.$putCase // the boolean is used to know if the modifiers should be reset + consumeFormalParameter(); $break ./ + +ClassTypeList -> ClassTypeElt +ClassTypeList ::= ClassTypeList ',' ClassTypeElt +/.$putCase consumeClassTypeList(); $break ./ + +ClassTypeElt ::= ClassType +/.$putCase consumeClassTypeElt(); $break ./ + + +MethodBody ::= NestedMethod '{' BlockStatementsopt '}' +/.$putCase consumeMethodBody(); $break ./ + +NestedMethod ::= $empty +/.$putCase consumeNestedMethod(); $break ./ + +--18.8.4 Productions from 8.5: Static Initializers + +StaticInitializer ::= StaticOnly Block +/.$putCase consumeStaticInitializer(); $break./ + +StaticOnly ::= 'static' +/.$putCase consumeStaticOnly(); $break ./ + +--18.8.5 Productions from 8.6: Constructor Declarations +--ConstructorModifier ::= +-- 'public' +-- | 'protected' +-- | 'private' +-- +-- +ConstructorDeclaration ::= ConstructorHeader ConstructorBody +/.$putCase consumeConstructorDeclaration() ; $break ./ + +-- These rules are added to be able to parse constructors with no body +ConstructorDeclaration ::= ConstructorHeader ';' +/.$putCase consumeInvalidConstructorDeclaration() ; $break ./ + +-- the rules ExplicitConstructorInvocationopt has been expanded +-- in the rule below in order to make the grammar lalr(1). +-- ConstructorBody ::= '{' ExplicitConstructorInvocationopt BlockStatementsopt '}' +-- Other inlining has occured into the next rule too.... + +ConstructorBody ::= NestedMethod '{' ConstructorBlockStatementsopt '}' +/.$putCase consumeConstructorBody(); $break ./ + +ConstructorBlockStatementsopt -> BlockStatementsopt + +ConstructorBlockStatementsopt -> ExplicitConstructorInvocation + +ConstructorBlockStatementsopt ::= ExplicitConstructorInvocation BlockStatements +/.$putCase consumeConstructorBlockStatements(); $break ./ + +ExplicitConstructorInvocation ::= 'this' '(' ArgumentListopt ')' ';' +/.$putCase consumeExplicitConstructorInvocation(0,ExplicitConstructorCall.This); $break ./ + +ExplicitConstructorInvocation ::= 'super' '(' ArgumentListopt ')' ';' +/.$putCase consumeExplicitConstructorInvocation(0,ExplicitConstructorCall.Super); $break ./ + +--1.1 feature +ExplicitConstructorInvocation ::= Primary '.' 'super' '(' ArgumentListopt ')' ';' +/.$putCase consumeExplicitConstructorInvocation(1, ExplicitConstructorCall.Super); $break ./ + +--1.1 feature +ExplicitConstructorInvocation ::= Name '.' 'super' '(' ArgumentListopt ')' ';' +/.$putCase consumeExplicitConstructorInvocation(2, ExplicitConstructorCall.Super); $break ./ + +--1.1 feature +ExplicitConstructorInvocation ::= Primary '.' 'this' '(' ArgumentListopt ')' ';' +/.$putCase consumeExplicitConstructorInvocation(1, ExplicitConstructorCall.This); $break ./ + +--1.1 feature +ExplicitConstructorInvocation ::= Name '.' 'this' '(' ArgumentListopt ')' ';' +/.$putCase consumeExplicitConstructorInvocation(2, ExplicitConstructorCall.This); $break ./ + +--18.9 Productions from 9: Interface Declarations + +--18.9.1 Productions from 9.1: Interface Declarations +--InterfaceModifier ::= +-- 'public' +-- | 'abstract' +-- +InterfaceDeclaration ::= InterfaceHeader InterfaceBody +/.$putCase consumeInterfaceDeclaration(); $break ./ + +InterfaceHeader ::= InterfaceHeaderName InterfaceHeaderExtendsopt +/.$putCase consumeInterfaceHeader(); $break ./ + +InterfaceHeaderName ::= Modifiersopt 'interface' 'Identifier' +/.$putCase consumeInterfaceHeaderName(); $break ./ + +-- This rule will be used to accept inner local interface and then report a relevant error message +InvalidInterfaceDeclaration -> InterfaceHeader InterfaceBody + +InterfaceHeaderExtends ::= 'extends' InterfaceTypeList +/.$putCase consumeInterfaceHeaderExtends(); $break ./ + +InterfaceBody ::= '{' InterfaceMemberDeclarationsopt '}' + +InterfaceMemberDeclarations -> InterfaceMemberDeclaration +InterfaceMemberDeclarations ::= InterfaceMemberDeclarations InterfaceMemberDeclaration +/.$putCase consumeInterfaceMemberDeclarations(); $break ./ + +--same as for class members +InterfaceMemberDeclaration ::= ';' +/.$putCase consumeEmptyInterfaceMemberDeclaration(); $break ./ + +-- This rule is added to be able to parse non abstract method inside interface and then report a relevent error message +InvalidMethodDeclaration -> MethodHeader MethodBody + +InterfaceMemberDeclaration -> ConstantDeclaration +InterfaceMemberDeclaration ::= InvalidMethodDeclaration +/.$putCase ignoreMethodBody(); $break ./ + +-- These rules are added to be able to parse constructors inside interface and then report a relevent error message +InvalidConstructorDeclaration ::= ConstructorHeader ConstructorBody +/.$putCase ignoreInvalidConstructorDeclaration(true); $break ./ + +InvalidConstructorDeclaration ::= ConstructorHeader ';' +/.$putCase ignoreInvalidConstructorDeclaration(false); $break ./ + +InterfaceMemberDeclaration -> AbstractMethodDeclaration +InterfaceMemberDeclaration -> InvalidConstructorDeclaration + +--1.1 feature +InterfaceMemberDeclaration -> ClassDeclaration +--1.1 feature +InterfaceMemberDeclaration -> InterfaceDeclaration + +ConstantDeclaration -> FieldDeclaration + +ArrayInitializer ::= '{' ,opt '}' +/.$putCase consumeEmptyArrayInitializer(); $break ./ +ArrayInitializer ::= '{' VariableInitializers '}' +/.$putCase consumeArrayInitializer(); $break ./ +ArrayInitializer ::= '{' VariableInitializers , '}' +/.$putCase consumeArrayInitializer(); $break ./ + +VariableInitializers ::= VariableInitializer +VariableInitializers ::= VariableInitializers ',' VariableInitializer +/.$putCase consumeVariableInitializers(); $break ./ + +Block ::= OpenBlock '{' BlockStatementsopt '}' +/.$putCase consumeBlock(); $break ./ +OpenBlock ::= $empty +/.$putCase consumeOpenBlock() ; $break ./ + +BlockStatements -> BlockStatement +BlockStatements ::= BlockStatements BlockStatement +/.$putCase consumeBlockStatements() ; $break ./ + +BlockStatement -> LocalVariableDeclarationStatement +BlockStatement -> Statement +--1.1 feature +BlockStatement -> ClassDeclaration +BlockStatement ::= InvalidInterfaceDeclaration +/.$putCase ignoreInterfaceDeclaration(); $break ./ + +LocalVariableDeclarationStatement ::= LocalVariableDeclaration ';' +/.$putCase consumeLocalVariableDeclarationStatement(); $break ./ + +LocalVariableDeclaration ::= Type PushModifiers VariableDeclarators +/.$putCase consumeLocalVariableDeclaration(); $break ./ + +-- 1.1 feature +-- The modifiers part of this rule makes the grammar more permissive. +-- The only modifier here is final. We put Modifiers to allow multiple modifiers +-- This will require to check the validity of the modifier + +LocalVariableDeclaration ::= Modifiers Type PushModifiers VariableDeclarators +/.$putCase consumeLocalVariableDeclaration(); $break ./ + +PushModifiers ::= $empty +/.$putCase consumePushModifiers(); $break ./ + +Statement -> StatementWithoutTrailingSubstatement +Statement -> LabeledStatement +Statement -> IfThenStatement +Statement -> IfThenElseStatement +Statement -> WhileStatement +Statement -> ForStatement + +StatementNoShortIf -> StatementWithoutTrailingSubstatement +StatementNoShortIf -> LabeledStatementNoShortIf +StatementNoShortIf -> IfThenElseStatementNoShortIf +StatementNoShortIf -> WhileStatementNoShortIf +StatementNoShortIf -> ForStatementNoShortIf + +StatementWithoutTrailingSubstatement -> AssertStatement +StatementWithoutTrailingSubstatement -> Block +StatementWithoutTrailingSubstatement -> EmptyStatement +StatementWithoutTrailingSubstatement -> ExpressionStatement +StatementWithoutTrailingSubstatement -> SwitchStatement +StatementWithoutTrailingSubstatement -> DoStatement +StatementWithoutTrailingSubstatement -> BreakStatement +StatementWithoutTrailingSubstatement -> ContinueStatement +StatementWithoutTrailingSubstatement -> ReturnStatement +StatementWithoutTrailingSubstatement -> SynchronizedStatement +StatementWithoutTrailingSubstatement -> ThrowStatement +StatementWithoutTrailingSubstatement -> TryStatement + +EmptyStatement ::= ';' +/.$putCase consumeEmptyStatement(); $break ./ + +LabeledStatement ::= 'Identifier' ':' Statement +/.$putCase consumeStatementLabel() ; $break ./ + +LabeledStatementNoShortIf ::= 'Identifier' ':' StatementNoShortIf +/.$putCase consumeStatementLabel() ; $break ./ + +ExpressionStatement ::= StatementExpression ';' +/. $putCase consumeExpressionStatement(); $break ./ + +StatementExpression ::= Assignment +StatementExpression ::= PreIncrementExpression +StatementExpression ::= PreDecrementExpression +StatementExpression ::= PostIncrementExpression +StatementExpression ::= PostDecrementExpression +StatementExpression ::= MethodInvocation +StatementExpression ::= ClassInstanceCreationExpression + +IfThenStatement ::= 'if' '(' Expression ')' Statement +/.$putCase consumeStatementIfNoElse(); $break ./ + +IfThenElseStatement ::= 'if' '(' Expression ')' StatementNoShortIf 'else' Statement +/.$putCase consumeStatementIfWithElse(); $break ./ + +IfThenElseStatementNoShortIf ::= 'if' '(' Expression ')' StatementNoShortIf 'else' StatementNoShortIf +/.$putCase consumeStatementIfWithElse(); $break ./ + +SwitchStatement ::= 'switch' OpenBlock '(' Expression ')' SwitchBlock +/.$putCase consumeStatementSwitch() ; $break ./ + +SwitchBlock ::= '{' '}' +/.$putCase consumeEmptySwitchBlock() ; $break ./ + +SwitchBlock ::= '{' SwitchBlockStatements '}' +SwitchBlock ::= '{' SwitchLabels '}' +SwitchBlock ::= '{' SwitchBlockStatements SwitchLabels '}' +/.$putCase consumeSwitchBlock() ; $break ./ + +SwitchBlockStatements -> SwitchBlockStatement +SwitchBlockStatements ::= SwitchBlockStatements SwitchBlockStatement +/.$putCase consumeSwitchBlockStatements() ; $break ./ + +SwitchBlockStatement ::= SwitchLabels BlockStatements +/.$putCase consumeSwitchBlockStatement() ; $break ./ + +SwitchLabels -> SwitchLabel +SwitchLabels ::= SwitchLabels SwitchLabel +/.$putCase consumeSwitchLabels() ; $break ./ + +SwitchLabel ::= 'case' ConstantExpression ':' +/. $putCase consumeCaseLabel(); $break ./ + +SwitchLabel ::= 'default' ':' +/. $putCase consumeDefaultLabel(); $break ./ + +WhileStatement ::= 'while' '(' Expression ')' Statement +/.$putCase consumeStatementWhile() ; $break ./ + +WhileStatementNoShortIf ::= 'while' '(' Expression ')' StatementNoShortIf +/.$putCase consumeStatementWhile() ; $break ./ + +DoStatement ::= 'do' Statement 'while' '(' Expression ')' ';' +/.$putCase consumeStatementDo() ; $break ./ + +ForStatement ::= 'for' '(' ForInitopt ';' Expressionopt ';' ForUpdateopt ')' Statement +/.$putCase consumeStatementFor() ; $break ./ +ForStatementNoShortIf ::= 'for' '(' ForInitopt ';' Expressionopt ';' ForUpdateopt ')' StatementNoShortIf +/.$putCase consumeStatementFor() ; $break ./ + +--the minus one allows to avoid a stack-to-stack transfer +ForInit ::= StatementExpressionList +/.$putCase consumeForInit() ; $break ./ +ForInit -> LocalVariableDeclaration + +ForUpdate -> StatementExpressionList + +StatementExpressionList -> StatementExpression +StatementExpressionList ::= StatementExpressionList ',' StatementExpression +/.$putCase consumeStatementExpressionList() ; $break ./ + +-- 1.4 feature +AssertStatement ::= 'assert' Expression ';' +/.$putCase consumeSimpleAssertStatement() ; $break ./ + +AssertStatement ::= 'assert' Expression ':' Expression ';' +/.$putCase consumeAssertStatement() ; $break ./ + +BreakStatement ::= 'break' ';' +/.$putCase consumeStatementBreak() ; $break ./ + +BreakStatement ::= 'break' Identifier ';' +/.$putCase consumeStatementBreakWithLabel() ; $break ./ + +ContinueStatement ::= 'continue' ';' +/.$putCase consumeStatementContinue() ; $break ./ + +ContinueStatement ::= 'continue' Identifier ';' +/.$putCase consumeStatementContinueWithLabel() ; $break ./ + +ReturnStatement ::= 'return' Expressionopt ';' +/.$putCase consumeStatementReturn() ; $break ./ + +ThrowStatement ::= 'throw' Expression ';' +/.$putCase consumeStatementThrow(); +$break ./ + +SynchronizedStatement ::= OnlySynchronized '(' Expression ')' Block +/.$putCase consumeStatementSynchronized(); $break ./ +OnlySynchronized ::= 'synchronized' +/.$putCase consumeOnlySynchronized(); $break ./ + + +TryStatement ::= 'try' Block Catches +/.$putCase consumeStatementTry(false); $break ./ +TryStatement ::= 'try' Block Catchesopt Finally +/.$putCase consumeStatementTry(true); $break ./ + +Catches -> CatchClause +Catches ::= Catches CatchClause +/.$putCase consumeCatches(); $break ./ + +CatchClause ::= 'catch' '(' FormalParameter ')' Block +/.$putCase consumeStatementCatch() ; $break ./ + +Finally ::= 'finally' Block + +--18.12 Productions from 14: Expressions + +--for source positionning purpose +PushLPAREN ::= '(' +/.$putCase consumeLeftParen(); $break ./ +PushRPAREN ::= ')' +/.$putCase consumeRightParen(); $break ./ + +Primary -> PrimaryNoNewArray +Primary -> ArrayCreationExpression + +PrimaryNoNewArray -> Literal +PrimaryNoNewArray ::= 'this' +/.$putCase consumePrimaryNoNewArrayThis(); $break ./ + +PrimaryNoNewArray ::= PushLPAREN Expression PushRPAREN +/.$putCase consumePrimaryNoNewArray(); $break ./ + +PrimaryNoNewArray -> ClassInstanceCreationExpression +PrimaryNoNewArray -> FieldAccess +--1.1 feature +PrimaryNoNewArray ::= Name '.' 'this' +/.$putCase consumePrimaryNoNewArrayNameThis(); $break ./ +PrimaryNoNewArray ::= Name '.' 'super' +/.$putCase consumePrimaryNoNewArrayNameSuper(); $break ./ + +--1.1 feature +--PrimaryNoNewArray ::= Type '.' 'class' +--inline Type in the previous rule in order to make the grammar LL1 instead +-- of LL2. The result is the 3 next rules. +PrimaryNoNewArray ::= Name '.' 'class' +/.$putCase consumePrimaryNoNewArrayName(); $break ./ + +PrimaryNoNewArray ::= ArrayType '.' 'class' +/.$putCase consumePrimaryNoNewArrayArrayType(); $break ./ + +PrimaryNoNewArray ::= PrimitiveType '.' 'class' +/.$putCase consumePrimaryNoNewArrayPrimitiveType(); $break ./ + +PrimaryNoNewArray -> MethodInvocation +PrimaryNoNewArray -> ArrayAccess + +--1.1 feature +-- +-- In Java 1.0 a ClassBody could not appear at all in a +-- ClassInstanceCreationExpression. +-- + +AllocationHeader ::= 'new' ClassType '(' ArgumentListopt ')' +/.$putCase consumeAllocationHeader(); $break ./ + +ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt +/.$putCase consumeClassInstanceCreationExpression(); $break ./ +--1.1 feature + +ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt +/.$putCase consumeClassInstanceCreationExpressionQualified() ; $break ./ + +--1.1 feature +ClassInstanceCreationExpression ::= ClassInstanceCreationExpressionName 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt +/.$putCase consumeClassInstanceCreationExpressionQualified() ; $break ./ + +ClassInstanceCreationExpressionName ::= Name '.' +/.$putCase consumeClassInstanceCreationExpressionName() ; $break ./ + +ClassBodyopt ::= $empty --test made using null as contents +/.$putCase consumeClassBodyopt(); $break ./ +ClassBodyopt ::= EnterAnonymousClassBody ClassBody + +EnterAnonymousClassBody ::= $empty +/.$putCase consumeEnterAnonymousClassBody(); $break ./ + +ArgumentList ::= Expression +ArgumentList ::= ArgumentList ',' Expression +/.$putCase consumeArgumentList(); $break ./ + +--Thess rules are re-written in order to be ll1 +--ArrayCreationExpression ::= 'new' ArrayType ArrayInitializer +--ArrayCreationExpression ::= 'new' PrimitiveType DimExprs Dimsopt +--ArrayCreationExpression ::= 'new' ClassOrInterfaceType DimExprs Dimsopt +--DimExprs ::= DimExpr +--DimExprs ::= DimExprs DimExpr + +ArrayCreationExpression ::= 'new' PrimitiveType DimWithOrWithOutExprs ArrayInitializeropt +/.$putCase consumeArrayCreationExpression(); $break ./ +ArrayCreationExpression ::= 'new' ClassOrInterfaceType DimWithOrWithOutExprs ArrayInitializeropt +/.$putCase consumeArrayCreationExpression(); $break ./ + +DimWithOrWithOutExprs ::= DimWithOrWithOutExpr +DimWithOrWithOutExprs ::= DimWithOrWithOutExprs DimWithOrWithOutExpr +/.$putCase consumeDimWithOrWithOutExprs(); $break ./ + +DimWithOrWithOutExpr ::= '[' Expression ']' +DimWithOrWithOutExpr ::= '[' ']' +/. $putCase consumeDimWithOrWithOutExpr(); $break ./ +-- ----------------------------------------------- + +Dims ::= DimsLoop +/. $putCase consumeDims(); $break ./ +DimsLoop -> OneDimLoop +DimsLoop ::= DimsLoop OneDimLoop +OneDimLoop ::= '[' ']' +/. $putCase consumeOneDimLoop(); $break ./ + +FieldAccess ::= Primary '.' 'Identifier' +/.$putCase consumeFieldAccess(false); $break ./ + +FieldAccess ::= 'super' '.' 'Identifier' +/.$putCase consumeFieldAccess(true); $break ./ + +MethodInvocation ::= Name '(' ArgumentListopt ')' +/.$putCase consumeMethodInvocationName(); $break ./ + +MethodInvocation ::= Primary '.' 'Identifier' '(' ArgumentListopt ')' +/.$putCase consumeMethodInvocationPrimary(); $break ./ + +MethodInvocation ::= 'super' '.' 'Identifier' '(' ArgumentListopt ')' +/.$putCase consumeMethodInvocationSuper(); $break ./ + +ArrayAccess ::= Name '[' Expression ']' +/.$putCase consumeArrayAccess(true); $break ./ +ArrayAccess ::= PrimaryNoNewArray '[' Expression ']' +/.$putCase consumeArrayAccess(false); $break ./ + +PostfixExpression -> Primary +PostfixExpression ::= Name +/.$putCase consumePostfixExpression(); $break ./ +PostfixExpression -> PostIncrementExpression +PostfixExpression -> PostDecrementExpression + +PostIncrementExpression ::= PostfixExpression '++' +/.$putCase consumeUnaryExpression(OperatorExpression.PLUS,true); $break ./ + +PostDecrementExpression ::= PostfixExpression '--' +/.$putCase consumeUnaryExpression(OperatorExpression.MINUS,true); $break ./ + +--for source managment purpose +PushPosition ::= $empty + /.$putCase consumePushPosition(); $break ./ + +UnaryExpression -> PreIncrementExpression +UnaryExpression -> PreDecrementExpression +UnaryExpression ::= '+' PushPosition UnaryExpression +/.$putCase consumeUnaryExpression(OperatorExpression.PLUS); $break ./ +UnaryExpression ::= '-' PushPosition UnaryExpression +/.$putCase consumeUnaryExpression(OperatorExpression.MINUS); $break ./ +UnaryExpression -> UnaryExpressionNotPlusMinus + +PreIncrementExpression ::= '++' PushPosition UnaryExpression +/.$putCase consumeUnaryExpression(OperatorExpression.PLUS,false); $break ./ + +PreDecrementExpression ::= '--' PushPosition UnaryExpression +/.$putCase consumeUnaryExpression(OperatorExpression.MINUS,false); $break ./ + +UnaryExpressionNotPlusMinus -> PostfixExpression +UnaryExpressionNotPlusMinus ::= '~' PushPosition UnaryExpression +/.$putCase consumeUnaryExpression(OperatorExpression.TWIDDLE); $break ./ +UnaryExpressionNotPlusMinus ::= '!' PushPosition UnaryExpression +/.$putCase consumeUnaryExpression(OperatorExpression.NOT); $break ./ +UnaryExpressionNotPlusMinus -> CastExpression + +CastExpression ::= PushLPAREN PrimitiveType Dimsopt PushRPAREN UnaryExpression +/.$putCase consumeCastExpression(); $break ./ + CastExpression ::= PushLPAREN Name Dims PushRPAREN UnaryExpressionNotPlusMinus +/.$putCase consumeCastExpression(); $break ./ +-- Expression is here only in order to make the grammar LL1 +CastExpression ::= PushLPAREN Expression PushRPAREN UnaryExpressionNotPlusMinus +/.$putCase consumeCastExpressionLL1(); $break ./ + +MultiplicativeExpression -> UnaryExpression +MultiplicativeExpression ::= MultiplicativeExpression '*' UnaryExpression +/.$putCase consumeBinaryExpression(OperatorExpression.MULTIPLY); $break ./ +MultiplicativeExpression ::= MultiplicativeExpression '/' UnaryExpression +/.$putCase consumeBinaryExpression(OperatorExpression.DIVIDE); $break ./ +MultiplicativeExpression ::= MultiplicativeExpression '%' UnaryExpression +/.$putCase consumeBinaryExpression(OperatorExpression.REMAINDER); $break ./ + +AdditiveExpression -> MultiplicativeExpression +AdditiveExpression ::= AdditiveExpression '+' MultiplicativeExpression +/.$putCase consumeBinaryExpression(OperatorExpression.PLUS); $break ./ +AdditiveExpression ::= AdditiveExpression '-' MultiplicativeExpression +/.$putCase consumeBinaryExpression(OperatorExpression.MINUS); $break ./ + +ShiftExpression -> AdditiveExpression +ShiftExpression ::= ShiftExpression '<<' AdditiveExpression +/.$putCase consumeBinaryExpression(OperatorExpression.LEFT_SHIFT); $break ./ +ShiftExpression ::= ShiftExpression '>>' AdditiveExpression +/.$putCase consumeBinaryExpression(OperatorExpression.RIGHT_SHIFT); $break ./ +ShiftExpression ::= ShiftExpression '>>>' AdditiveExpression +/.$putCase consumeBinaryExpression(OperatorExpression.UNSIGNED_RIGHT_SHIFT); $break ./ + +RelationalExpression -> ShiftExpression +RelationalExpression ::= RelationalExpression '<' ShiftExpression +/.$putCase consumeBinaryExpression(OperatorExpression.LESS); $break ./ +RelationalExpression ::= RelationalExpression '>' ShiftExpression +/.$putCase consumeBinaryExpression(OperatorExpression.GREATER); $break ./ +RelationalExpression ::= RelationalExpression '<=' ShiftExpression +/.$putCase consumeBinaryExpression(OperatorExpression.LESS_EQUAL); $break ./ +RelationalExpression ::= RelationalExpression '>=' ShiftExpression +/.$putCase consumeBinaryExpression(OperatorExpression.GREATER_EQUAL); $break ./ +RelationalExpression ::= RelationalExpression 'instanceof' ReferenceType +/.$putCase consumeInstanceOfExpression(OperatorExpression.INSTANCEOF); $break ./ + +EqualityExpression -> RelationalExpression +EqualityExpression ::= EqualityExpression '==' RelationalExpression +/.$putCase consumeEqualityExpression(OperatorExpression.EQUAL_EQUAL); $break ./ +EqualityExpression ::= EqualityExpression '!=' RelationalExpression +/.$putCase consumeEqualityExpression(OperatorExpression.NOT_EQUAL); $break ./ + +AndExpression -> EqualityExpression +AndExpression ::= AndExpression '&' EqualityExpression +/.$putCase consumeBinaryExpression(OperatorExpression.AND); $break ./ + +ExclusiveOrExpression -> AndExpression +ExclusiveOrExpression ::= ExclusiveOrExpression '^' AndExpression +/.$putCase consumeBinaryExpression(OperatorExpression.XOR); $break ./ + +InclusiveOrExpression -> ExclusiveOrExpression +InclusiveOrExpression ::= InclusiveOrExpression '|' ExclusiveOrExpression +/.$putCase consumeBinaryExpression(OperatorExpression.OR); $break ./ + +ConditionalAndExpression -> InclusiveOrExpression +ConditionalAndExpression ::= ConditionalAndExpression '&&' InclusiveOrExpression +/.$putCase consumeBinaryExpression(OperatorExpression.AND_AND); $break ./ + +ConditionalOrExpression -> ConditionalAndExpression +ConditionalOrExpression ::= ConditionalOrExpression '||' ConditionalAndExpression +/.$putCase consumeBinaryExpression(OperatorExpression.OR_OR); $break ./ + +ConditionalExpression -> ConditionalOrExpression +ConditionalExpression ::= ConditionalOrExpression '?' Expression ':' ConditionalExpression +/.$putCase consumeConditionalExpression(OperatorExpression.QUESTIONCOLON) ; $break ./ + +AssignmentExpression -> ConditionalExpression +AssignmentExpression -> Assignment + +Assignment ::= LeftHandSide AssignmentOperator AssignmentExpression +/.$putCase consumeAssignment(); $break ./ + +-- this rule is added to parse an array initializer in a assigment and then report a syntax error knowing the exact senario +InvalidArrayInitializerAssignement ::= LeftHandSide AssignmentOperator ArrayInitializer +Assignment ::= InvalidArrayInitializerAssignement +/.$putcase ignoreExpressionAssignment();$break ./ + +LeftHandSide ::= Name +/.$putCase consumeLeftHandSide(); $break ./ +LeftHandSide -> FieldAccess +LeftHandSide -> ArrayAccess + +AssignmentOperator ::= '=' +/.$putCase consumeAssignmentOperator(EQUAL); $break ./ +AssignmentOperator ::= '*=' +/.$putCase consumeAssignmentOperator(MULTIPLY); $break ./ +AssignmentOperator ::= '/=' +/.$putCase consumeAssignmentOperator(DIVIDE); $break ./ +AssignmentOperator ::= '%=' +/.$putCase consumeAssignmentOperator(REMAINDER); $break ./ +AssignmentOperator ::= '+=' +/.$putCase consumeAssignmentOperator(PLUS); $break ./ +AssignmentOperator ::= '-=' +/.$putCase consumeAssignmentOperator(MINUS); $break ./ +AssignmentOperator ::= '<<=' +/.$putCase consumeAssignmentOperator(LEFT_SHIFT); $break ./ +AssignmentOperator ::= '>>=' +/.$putCase consumeAssignmentOperator(RIGHT_SHIFT); $break ./ +AssignmentOperator ::= '>>>=' +/.$putCase consumeAssignmentOperator(UNSIGNED_RIGHT_SHIFT); $break ./ +AssignmentOperator ::= '&=' +/.$putCase consumeAssignmentOperator(AND); $break ./ +AssignmentOperator ::= '^=' +/.$putCase consumeAssignmentOperator(XOR); $break ./ +AssignmentOperator ::= '|=' +/.$putCase consumeAssignmentOperator(OR); $break ./ + +Expression -> AssignmentExpression + +ConstantExpression -> Expression + +-- The following rules are for optional nonterminals. +-- + +PackageDeclarationopt -> $empty +PackageDeclarationopt -> PackageDeclaration + +ClassHeaderExtendsopt ::= $empty +ClassHeaderExtendsopt -> ClassHeaderExtends + +Expressionopt ::= $empty +/.$putCase consumeEmptyExpression(); $break ./ +Expressionopt -> Expression + + +--------------------------------------------------------------------------------------- +-- +-- The rules below are for optional terminal symbols. An optional comma, +-- is only used in the context of an array initializer - It is a +-- "syntactic sugar" that otherwise serves no other purpose. By contrast, +-- an optional identifier is used in the definition of a break and +-- continue statement. When the identifier does not appear, a NULL +-- is produced. When the identifier is present, the user should use the +-- corresponding TOKEN(i) method. See break statement as an example. +-- +--------------------------------------------------------------------------------------- + +,opt -> $empty +,opt -> , + +ImportDeclarationsopt ::= $empty +/.$putCase consumeEmptyImportDeclarationsopt(); $break ./ +ImportDeclarationsopt ::= ImportDeclarations +/.$putCase consumeImportDeclarationsopt(); $break ./ + + +TypeDeclarationsopt ::= $empty +/.$putCase consumeEmptyTypeDeclarationsopt(); $break ./ +TypeDeclarationsopt ::= TypeDeclarations +/.$putCase consumeTypeDeclarationsopt(); $break ./ + +ClassBodyDeclarationsopt ::= $empty +/.$putCase consumeEmptyClassBodyDeclarationsopt(); $break ./ +ClassBodyDeclarationsopt ::= NestedType ClassBodyDeclarations +/.$putCase consumeClassBodyDeclarationsopt(); $break ./ + +Modifiersopt ::= $empty +/. $putCase consumeDefaultModifiers(); $break ./ +Modifiersopt ::= Modifiers +/.$putCase consumeModifiers(); $break ./ + +BlockStatementsopt ::= $empty +/.$putCase consumeEmptyBlockStatementsopt(); $break ./ +BlockStatementsopt -> BlockStatements + +Dimsopt ::= $empty +/. $putCase consumeEmptyDimsopt(); $break ./ +Dimsopt -> Dims + +ArgumentListopt ::= $empty +/. $putCase consumeEmptyArgumentListopt(); $break ./ +ArgumentListopt -> ArgumentList + +MethodHeaderThrowsClauseopt ::= $empty +MethodHeaderThrowsClauseopt -> MethodHeaderThrowsClause + +FormalParameterListopt ::= $empty +/.$putcase consumeFormalParameterListopt(); $break ./ +FormalParameterListopt -> FormalParameterList + +ClassHeaderImplementsopt ::= $empty +ClassHeaderImplementsopt -> ClassHeaderImplements + +InterfaceMemberDeclarationsopt ::= $empty +/. $putCase consumeEmptyInterfaceMemberDeclarationsopt(); $break ./ +InterfaceMemberDeclarationsopt ::= NestedType InterfaceMemberDeclarations +/. $putCase consumeInterfaceMemberDeclarationsopt(); $break ./ + +NestedType ::= $empty +/.$putCase consumeNestedType(); $break./ + +ForInitopt ::= $empty +/. $putCase consumeEmptyForInitopt(); $break ./ +ForInitopt -> ForInit + +ForUpdateopt ::= $empty +/. $putCase consumeEmptyForUpdateopt(); $break ./ + ForUpdateopt -> ForUpdate + +InterfaceHeaderExtendsopt ::= $empty +InterfaceHeaderExtendsopt -> InterfaceHeaderExtends + +Catchesopt ::= $empty +/. $putCase consumeEmptyCatchesopt(); $break ./ +Catchesopt -> Catches + +ArrayInitializeropt ::= $empty +/. $putCase consumeEmptyArrayInitializeropt(); $break ./ +ArrayInitializeropt -> ArrayInitializer + +/. } +} ./ + +--------------------------------------------------------------------------------------- + +$names + +-- BodyMarker ::= '"class Identifier { ... MethodHeader "' + +-- void ::= 'void' + +PLUS_PLUS ::= '++' +MINUS_MINUS ::= '--' +EQUAL_EQUAL ::= '==' +LESS_EQUAL ::= '<=' +GREATER_EQUAL ::= '>=' +NOT_EQUAL ::= '!=' +LEFT_SHIFT ::= '<<' +RIGHT_SHIFT ::= '>>' +UNSIGNED_RIGHT_SHIFT ::= '>>>' +PLUS_EQUAL ::= '+=' +MINUS_EQUAL ::= '-=' +MULTIPLY_EQUAL ::= '*=' +DIVIDE_EQUAL ::= '/=' +AND_EQUAL ::= '&=' +OR_EQUAL ::= '|=' +XOR_EQUAL ::= '^=' +REMAINDER_EQUAL ::= '%=' +LEFT_SHIFT_EQUAL ::= '<<=' +RIGHT_SHIFT_EQUAL ::= '>>=' +UNSIGNED_RIGHT_SHIFT_EQUAL ::= '>>>=' +OR_OR ::= '||' +AND_AND ::= '&&' + +PLUS ::= '+' +MINUS ::= '-' +NOT ::= '!' +REMAINDER ::= '%' +XOR ::= '^' +AND ::= '&' +MULTIPLY ::= '*' +OR ::= '|' +TWIDDLE ::= '~' +DIVIDE ::= '/' +GREATER ::= '>' +LESS ::= '<' +LPAREN ::= '(' +RPAREN ::= ')' +LBRACE ::= '{' +RBRACE ::= '}' +LBRACKET ::= '[' +RBRACKET ::= ']' +SEMICOLON ::= ';' +QUESTION ::= '?' +COLON ::= ':' +COMMA ::= ',' +DOT ::= '.' +EQUAL ::= '=' + +$end +-- need a carriage return after the $end +*/ +} +protected void ignoreExpressionAssignment() { + // Assignment ::= InvalidArrayInitializerAssignement + // encoded operator would be: intStack[intPtr] + intPtr--; + ArrayInitializer arrayInitializer = (ArrayInitializer) expressionStack[expressionPtr--]; + expressionLengthPtr -- ; + // report a syntax error and abort parsing + problemReporter().arrayConstantsOnlyInArrayInitializers(arrayInitializer.sourceStart, arrayInitializer.sourceEnd); +} +protected void ignoreInterfaceDeclaration() { + // BlockStatement ::= InvalidInterfaceDeclaration + //InterfaceDeclaration ::= Modifiersopt 'interface' 'Identifier' ExtendsInterfacesopt InterfaceHeader InterfaceBody + + // length declarations + int length; + if ((length = astLengthStack[astLengthPtr--]) != 0) { + //there are length declarations + //dispatch according to the type of the declarations + dispatchDeclarationInto(length); + } + + flushAnnotationsDefinedPriorTo(endStatementPosition); + + // report the problem and continue parsing + TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr]; + typeDecl.bodyEnd = endStatementPosition; + problemReporter().cannotDeclareLocalInterface(typeDecl.name, typeDecl.sourceStart, typeDecl.sourceEnd); + + // mark fields and initializer with local type mark if needed + markFieldsWithLocalType(typeDecl); + + // remove the ast node created in interface header + astPtr--; + // Don't create an astnode for this inner interface, but have to push + // a 0 on the astLengthStack to be consistent with the reduction made + // at the end of the method: + // public void parse(MethodDeclaration md, CompilationUnitDeclaration unit) + pushOnAstLengthStack(0); +} +protected void ignoreInvalidConstructorDeclaration(boolean hasBody) { + // InvalidConstructorDeclaration ::= ConstructorHeader ConstructorBody ==> true + // InvalidConstructorDeclaration ::= ConstructorHeader ';' ==> false + + /* + astStack : modifiers arguments throws statements + identifierStack : name + ==> + astStack : MethodDeclaration + identifierStack : + */ + + //must provide a default constructor call when needed + + if (hasBody) { + // pop the position of the { (body of the method) pushed in block decl + intPtr--; + } + + //statements + if (hasBody) { + realBlockPtr--; + } + + int length; + if (hasBody && ((length = astLengthStack[astLengthPtr--]) != 0)) { + astPtr -= length; + } +} +protected void ignoreMethodBody() { + // InterfaceMemberDeclaration ::= InvalidMethodDeclaration + + /* + astStack : modifiers arguments throws statements + identifierStack : type name + intStack : dim dim dim + ==> + astStack : MethodDeclaration + identifierStack : + intStack : + */ + + // pop the position of the { (body of the method) pushed in block decl + intPtr--; + // retrieve end position of method declarator + + //statements + realBlockPtr--; + int length; + if ((length = astLengthStack[astLengthPtr--]) != 0) { + astPtr -= length; + } + + //watch for } that could be given as a unicode ! ( u007D is '}' ) + MethodDeclaration md = (MethodDeclaration) astStack[astPtr]; + md.bodyEnd = endPosition; + md.declarationSourceEnd = flushAnnotationsDefinedPriorTo(endStatementPosition); + + // report the problem and continue the parsing - narrowing the problem onto the method + problemReporter().abstractMethodNeedingNoBody(md); +} +public void initialize() { + //positionning the parser for a new compilation unit + //avoiding stack reallocation and all that.... + astPtr = -1; + astLengthPtr = -1; + expressionPtr = -1; + expressionLengthPtr = -1; + identifierPtr = -1; + identifierLengthPtr = -1; + intPtr = -1; + nestedMethod[nestedType = 0] = 0; // need to reset for further reuse + variablesCounter[nestedType] = 0; + dimensions = 0 ; + realBlockPtr = -1; + compilationUnit = null; + referenceContext = null; + endStatementPosition = 0; + + //remove objects from stack too, while the same parser/compiler couple is + //re-used between two compilations .... + + int astLength = astStack.length; + if (noAstNodes.length < astLength){ + noAstNodes = new AstNode[astLength]; + //System.out.println("Resized AST stacks : "+ astLength); + + } + System.arraycopy(noAstNodes, 0, astStack, 0, astLength); + + int expressionLength = expressionStack.length; + if (noExpressions.length < expressionLength){ + noExpressions = new Expression[expressionLength]; + //System.out.println("Resized EXPR stacks : "+ expressionLength); + } + System.arraycopy(noExpressions, 0, expressionStack, 0, expressionLength); + + // reset scanner state + scanner.commentPtr = -1; + scanner.eofPosition = Integer.MAX_VALUE; + + resetModifiers(); + + // recovery + lastCheckPoint = -1; + currentElement = null; + restartRecovery = false; + hasReportedError = false; + recoveredStaticInitializerStart = 0; + lastIgnoredToken = -1; + lastErrorEndPosition = -1; + listLength = 0; +} +public void initializeScanner(){ + this.scanner = new Scanner(false, false, this.problemReporter.options.getNonExternalizedStringLiteralSeverity() != ProblemSeverities.Ignore , this.assertMode); +} +public final static void initTables() throws java.io.IOException { + + final String prefix = FILEPREFIX; + int i = 0; + lhs = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + char[] chars = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + check_table = new short[chars.length]; + for (int c = chars.length; c-- > 0;) { + check_table[c] = (short) (chars[c] - 32768); + } + asb = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + asr = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + symbol_index = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + action = lhs; +} +public final void jumpOverMethodBody() { + //on diet parsing.....do not buffer method statements + + //the scanner.diet is reinitialized to false + //automatically by the scanner once it has jumped over + //the statements + + if (diet && (dietInt == 0)) + scanner.diet = true; +} +protected void markCurrentMethodWithLocalType() { + if (this.currentElement != null) return; // this is already done in the recovery code + for (int i = this.astPtr; i >= 0; i--) { + AstNode node = this.astStack[i]; + if (node instanceof AbstractMethodDeclaration + || node instanceof TypeDeclaration) { // mark type for now: all fields will be marked when added to this type + node.bits |= AstNode.HasLocalTypeMASK; + return; + } + } + // default to reference context (case of parse method body) + if (this.referenceContext instanceof AbstractMethodDeclaration + || this.referenceContext instanceof TypeDeclaration) { + ((AstNode)this.referenceContext).bits |= AstNode.HasLocalTypeMASK; + } +} +protected void markFieldsWithLocalType(TypeDeclaration type) { + if (type.fields == null || (type.bits & AstNode.HasLocalTypeMASK) == 0) return; + for (int i = 0, length = type.fields.length; i < length; i++) { + type.fields[i].bits |= AstNode.HasLocalTypeMASK; + } +} +/* + * Move checkpoint location (current implementation is moving it by one token) + * + * Answers true if successfully moved checkpoint (i.e. did not attempt to move it + * beyond end of file). + */ +protected boolean moveRecoveryCheckpoint() { + + int pos = lastCheckPoint; + /* reset scanner, and move checkpoint by one token */ + scanner.startPosition = pos; + scanner.currentPosition = pos; + scanner.diet = false; // quit jumping over method bodies + + /* if about to restart, then no need to shift token */ + if (restartRecovery){ + lastIgnoredToken = -1; + return true; + } + + /* protect against shifting on an invalid token */ + lastIgnoredToken = nextIgnoredToken; + nextIgnoredToken = -1; + do { + try { + nextIgnoredToken = scanner.getNextToken(); + if(scanner.currentPosition == scanner.startPosition){ + scanner.currentPosition++; // on fake completion identifier + nextIgnoredToken = -1; + } + + } catch(InvalidInputException e){ + pos = scanner.currentPosition; + } + } while (nextIgnoredToken < 0); + + if (nextIgnoredToken == TokenNameEOF) { // no more recovery after this point + if (currentToken == TokenNameEOF) { // already tried one iteration on EOF + return false; + } + } + lastCheckPoint = scanner.currentPosition; + + /* reset scanner again to previous checkpoint location*/ + scanner.startPosition = pos; + scanner.currentPosition = pos; + scanner.commentPtr = -1; + + return true; + +/* + The following implementation moves the checkpoint location by one line: + + int pos = lastCheckPoint; + // reset scanner, and move checkpoint by one token + scanner.startPosition = pos; + scanner.currentPosition = pos; + scanner.diet = false; // quit jumping over method bodies + + // if about to restart, then no need to shift token + if (restartRecovery){ + lastIgnoredToken = -1; + return true; + } + + // protect against shifting on an invalid token + lastIgnoredToken = nextIgnoredToken; + nextIgnoredToken = -1; + + boolean wasTokenizingWhiteSpace = scanner.tokenizeWhiteSpace; + scanner.tokenizeWhiteSpace = true; + checkpointMove: + do { + try { + nextIgnoredToken = scanner.getNextToken(); + switch(nextIgnoredToken){ + case Scanner.TokenNameWHITESPACE : + if(scanner.getLineNumber(scanner.startPosition) + == scanner.getLineNumber(scanner.currentPosition)){ + nextIgnoredToken = -1; + } + break; + case TokenNameSEMICOLON : + case TokenNameLBRACE : + case TokenNameRBRACE : + break; + case TokenNameIdentifier : + if(scanner.currentPosition == scanner.startPosition){ + scanner.currentPosition++; // on fake completion identifier + } + default: + nextIgnoredToken = -1; + break; + case TokenNameEOF : + break checkpointMove; + } + } catch(InvalidInputException e){ + pos = scanner.currentPosition; + } + } while (nextIgnoredToken < 0); + scanner.tokenizeWhiteSpace = wasTokenizingWhiteSpace; + + if (nextIgnoredToken == TokenNameEOF) { // no more recovery after this point + if (currentToken == TokenNameEOF) { // already tried one iteration on EOF + return false; + } + } + lastCheckPoint = scanner.currentPosition; + + // reset scanner again to previous checkpoint location + scanner.startPosition = pos; + scanner.currentPosition = pos; + scanner.commentPtr = -1; + + return true; +*/ +} +protected MessageSend newMessageSend() { + // '(' ArgumentListopt ')' + // the arguments are on the expression stack + + MessageSend m = new MessageSend(); + int length; + if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) { + expressionPtr -= length; + System.arraycopy( + expressionStack, + expressionPtr + 1, + m.arguments = new Expression[length], + 0, + length); + }; + return m; +} +protected static int ntAction(int state, int sym) { + return action[state + sym]; +} +private final void optimizedConcatNodeLists() { + /*back from a recursive loop. Virtualy group the + astNode into an array using astLengthStack*/ + + /* + * This is a case where you have two sublists into the astStack that you want + * to merge in one list. There is no action required on the astStack. The only + * thing you need to do is merge the two lengths specified on the astStackLength. + * The top two length are for example: + * ... p n + * and you want to result in a list like: + * ... n+p + * This means that the p could be equals to 0 in case there is no astNode pushed + * on the astStack. + * Look at the InterfaceMemberDeclarations for an example. + * This case optimizes the fact that p == 1. + */ + + astLengthStack[--astLengthPtr]++; +} +protected static int original_state(int state) { + return -check(state); +} +/*main loop of the automat +When a rule is reduced, the method consumeRule(int) is called with the number +of the consumed rule. When a terminal is consumed, the method consumeToken(int) is +called in order to remember (when needed) the consumed token */ +// (int)asr[asi(act)] +// name[symbol_index[currentKind]] +protected void parse() { + + hasReportedError = false; + int act = START_STATE; + stateStackTop = -1; + currentToken = getFirstToken(); + ProcessTerminals : for (;;) { + try { + stack[++stateStackTop] = act; + } catch (IndexOutOfBoundsException e) { + int oldStackLength = stack.length; + int oldStack[] = stack; + stack = new int[oldStackLength + StackIncrement]; + System.arraycopy(oldStack, 0, stack, 0, oldStackLength); + stack[stateStackTop] = act; + }; + + act = tAction(act, currentToken); + + if (act == ERROR_ACTION || restartRecovery) { + int errorPos = scanner.currentPosition; + if (!hasReportedError){ + this.reportSyntaxError(ERROR_ACTION, currentToken, stateStackTop); + hasReportedError = true; + } + if (resumeOnSyntaxError()) { + if (act == ERROR_ACTION) lastErrorEndPosition = errorPos; + act = START_STATE; + stateStackTop = -1; + currentToken = getFirstToken(); + continue ProcessTerminals; + } else { + act = ERROR_ACTION; + } break ProcessTerminals; + } + if (act <= NUM_RULES) + stateStackTop--; + else + if (act > ERROR_ACTION) { /* shift-reduce */ + consumeToken(currentToken); + if (currentElement != null) this.recoveryTokenCheck(); + try{ + currentToken = scanner.getNextToken(); + } catch(InvalidInputException e){ + if (!hasReportedError){ + this.problemReporter().scannerError(this, e.getMessage()); + hasReportedError = true; + } + lastCheckPoint = scanner.currentPosition; + restartRecovery = true; + } + act -= ERROR_ACTION; + } else + if (act < ACCEPT_ACTION) { /* shift */ + consumeToken(currentToken); + if (currentElement != null) this.recoveryTokenCheck(); + try{ + currentToken = scanner.getNextToken(); + } catch(InvalidInputException e){ + if (!hasReportedError){ + this.problemReporter().scannerError(this, e.getMessage()); + hasReportedError = true; + } + lastCheckPoint = scanner.currentPosition; + restartRecovery = true; + } + continue ProcessTerminals; + } else + break ProcessTerminals; + + ProcessNonTerminals : do { /* reduce */ + consumeRule(act); + stateStackTop -= (rhs[act] - 1); + act = ntAction(stack[stateStackTop], lhs[act]); + } while (act <= NUM_RULES); + } + endParse(act); +} +// A P I + +public void parse(ConstructorDeclaration cd, CompilationUnitDeclaration unit) { + //only parse the method body of cd + //fill out its statements + + //convert bugs into parse error + + initialize(); + goForConstructorBody(); + nestedMethod[nestedType]++; + + referenceContext = cd; + compilationUnit = unit; + + scanner.resetTo(cd.sourceEnd + 1, cd.declarationSourceEnd); + try { + parse(); + } catch (AbortCompilation ex) { + lastAct = ERROR_ACTION; + } finally { + nestedMethod[nestedType]--; + } + + if (lastAct == ERROR_ACTION) { + initialize(); + return; + } + + //statements + cd.explicitDeclarations = realBlockStack[realBlockPtr--]; + int length; + if ((length = astLengthStack[astLengthPtr--]) != 0) { + astPtr -= length; + if (astStack[astPtr + 1] instanceof ExplicitConstructorCall) + //avoid a isSomeThing that would only be used here BUT what is faster between two alternatives ? + { + System.arraycopy( + astStack, + astPtr + 2, + cd.statements = new Statement[length - 1], + 0, + length - 1); + cd.constructorCall = (ExplicitConstructorCall) astStack[astPtr + 1]; + } else { //need to add explicitly the super(); + System.arraycopy( + astStack, + astPtr + 1, + cd.statements = new Statement[length], + 0, + length); + cd.constructorCall = SuperReference.implicitSuperConstructorCall(); + } + } else { + cd.constructorCall = SuperReference.implicitSuperConstructorCall(); + } + + if (cd.constructorCall.sourceEnd == 0) { + cd.constructorCall.sourceEnd = cd.sourceEnd; + cd.constructorCall.sourceStart = cd.sourceStart; + } +} +// A P I + +public void parse( + Initializer ini, + TypeDeclaration type, + CompilationUnitDeclaration unit) { + //only parse the method body of md + //fill out method statements + + //convert bugs into parse error + + initialize(); + goForInitializer(); + nestedMethod[nestedType]++; + + referenceContext = type; + compilationUnit = unit; + + scanner.resetTo(ini.sourceStart, ini.sourceEnd); // just on the beginning { + try { + parse(); + } catch (AbortCompilation ex) { + lastAct = ERROR_ACTION; + } finally { + nestedMethod[nestedType]--; + } + + if (lastAct == ERROR_ACTION) { + return; + } + + ini.block = ((Initializer) astStack[astPtr]).block; + + // mark initializer with local type if one was found during parsing + if ((type.bits & AstNode.HasLocalTypeMASK) != 0) { + ini.bits |= AstNode.HasLocalTypeMASK; + } +} +// A P I + +public void parse(MethodDeclaration md, CompilationUnitDeclaration unit) { + //only parse the method body of md + //fill out method statements + + //convert bugs into parse error + + if (md.isAbstract()) + return; + if (md.isNative()) + return; + if ((md.modifiers & AccSemicolonBody) != 0) + return; + + initialize(); + goForMethodBody(); + nestedMethod[nestedType]++; + + referenceContext = md; + compilationUnit = unit; + + scanner.resetTo(md.sourceEnd + 1, md.declarationSourceEnd); + // reset the scanner to parser from { down to } + try { + parse(); + } catch (AbortCompilation ex) { + lastAct = ERROR_ACTION; + } finally { + nestedMethod[nestedType]--; + } + + if (lastAct == ERROR_ACTION) { + return; + } + + //refill statements + md.explicitDeclarations = realBlockStack[realBlockPtr--]; + int length; + if ((length = astLengthStack[astLengthPtr--]) != 0) + System.arraycopy( + astStack, + (astPtr -= length) + 1, + md.statements = new Statement[length], + 0, + length); +} +// A P I + +public CompilationUnitDeclaration parse( + ICompilationUnit sourceUnit, + CompilationResult compilationResult) { + // parses a compilation unit and manages error handling (even bugs....) + + CompilationUnitDeclaration unit; + try { + /* automaton initialization */ + initialize(); + goForCompilationUnit(); + + /* scanner initialization */ + scanner.setSource(sourceUnit.getContents()); + + /* unit creation */ + referenceContext = + compilationUnit = + new CompilationUnitDeclaration( + problemReporter, + compilationResult, + scanner.source.length); + /* run automaton */ + parse(); + } finally { + unit = compilationUnit; + compilationUnit = null; // reset parser + } + return unit; +} +// A P I + +public CompilationUnitDeclaration parse( + ICompilationUnit sourceUnit, + CompilationResult compilationResult, + int start, + int end) { + // parses a compilation unit and manages error handling (even bugs....) + + CompilationUnitDeclaration unit; + try { + /* automaton initialization */ + initialize(); + goForCompilationUnit(); + + /* scanner initialization */ + scanner.setSource(sourceUnit.getContents()); + scanner.resetTo(start, end); + /* unit creation */ + referenceContext = + compilationUnit = + new CompilationUnitDeclaration( + problemReporter, + compilationResult, + scanner.source.length); + /* run automaton */ + parse(); + } finally { + unit = compilationUnit; + compilationUnit = null; // reset parser + } + return unit; +} +/** + * Returns this parser's problem reporter initialized with its reference context. + * Also it is assumed that a problem is going to be reported, so initializes + * the compilation result's line positions. + */ +public ProblemReporter problemReporter(){ + if (scanner.recordLineSeparator) { + compilationUnit.compilationResult.lineSeparatorPositions = scanner.getLineEnds(); + } + problemReporter.referenceContext = referenceContext; + return problemReporter; +} +protected void pushIdentifier() { + /*push the consumeToken on the identifier stack. + Increase the total number of identifier in the stack. + identifierPtr points on the next top */ + + try { + identifierStack[++identifierPtr] = scanner.getCurrentIdentifierSource(); + identifierPositionStack[identifierPtr] = + (((long) scanner.startPosition) << 32) + (scanner.currentPosition - 1); + } catch (IndexOutOfBoundsException e) { + /*---stack reallaocation (identifierPtr is correct)---*/ + int oldStackLength = identifierStack.length; + char[][] oldStack = identifierStack; + identifierStack = new char[oldStackLength + 20][]; + System.arraycopy(oldStack, 0, identifierStack, 0, oldStackLength); + identifierStack[identifierPtr] = scanner.getCurrentTokenSource(); + /*identifier position stack*/ + long[] oldPos = identifierPositionStack; + identifierPositionStack = new long[oldStackLength + 20]; + System.arraycopy(oldPos, 0, identifierPositionStack, 0, oldStackLength); + identifierPositionStack[identifierPtr] = + (((long) scanner.startPosition) << 32) + (scanner.currentPosition - 1); + }; + + try { + identifierLengthStack[++identifierLengthPtr] = 1; + } catch (IndexOutOfBoundsException e) { + /*---stack reallocation (identifierLengthPtr is correct)---*/ + int oldStackLength = identifierLengthStack.length; + int oldStack[] = identifierLengthStack; + identifierLengthStack = new int[oldStackLength + 10]; + System.arraycopy(oldStack, 0, identifierLengthStack, 0, oldStackLength); + identifierLengthStack[identifierLengthPtr] = 1; + }; + +} +protected void pushIdentifier(int flag) { + /*push a special flag on the stack : + -zero stands for optional Name + -negative number for direct ref to base types. + identifierLengthPtr points on the top */ + + try { + identifierLengthStack[++identifierLengthPtr] = flag; + } catch (IndexOutOfBoundsException e) { + /*---stack reallaocation (identifierLengthPtr is correct)---*/ + int oldStackLength = identifierLengthStack.length; + int oldStack[] = identifierLengthStack; + identifierLengthStack = new int[oldStackLength + 10]; + System.arraycopy(oldStack, 0, identifierLengthStack, 0, oldStackLength); + identifierLengthStack[identifierLengthPtr] = flag; + }; + +} +protected void pushOnAstLengthStack(int pos) { + try { + astLengthStack[++astLengthPtr] = pos; + } catch (IndexOutOfBoundsException e) { + int oldStackLength = astLengthStack.length; + int[] oldPos = astLengthStack; + astLengthStack = new int[oldStackLength + StackIncrement]; + System.arraycopy(oldPos, 0, astLengthStack, 0, oldStackLength); + astLengthStack[astLengthPtr] = pos; + } +} +protected void pushOnAstStack(AstNode node) { + /*add a new obj on top of the ast stack + astPtr points on the top*/ + + try { + astStack[++astPtr] = node; + } catch (IndexOutOfBoundsException e) { + int oldStackLength = astStack.length; + AstNode[] oldStack = astStack; + astStack = new AstNode[oldStackLength + AstStackIncrement]; + System.arraycopy(oldStack, 0, astStack, 0, oldStackLength); + astPtr = oldStackLength; + astStack[astPtr] = node; + } + + try { + astLengthStack[++astLengthPtr] = 1; + } catch (IndexOutOfBoundsException e) { + int oldStackLength = astLengthStack.length; + int[] oldPos = astLengthStack; + astLengthStack = new int[oldStackLength + AstStackIncrement]; + System.arraycopy(oldPos, 0, astLengthStack, 0, oldStackLength); + astLengthStack[astLengthPtr] = 1; + } +} +protected void pushOnExpressionStack(Expression expr) { + + try { + expressionStack[++expressionPtr] = expr; + } catch (IndexOutOfBoundsException e) { + //expressionPtr is correct + int oldStackLength = expressionStack.length; + Expression[] oldStack = expressionStack; + expressionStack = new Expression[oldStackLength + ExpressionStackIncrement]; + System.arraycopy(oldStack, 0, expressionStack, 0, oldStackLength); + expressionStack[expressionPtr] = expr; + } + + try { + expressionLengthStack[++expressionLengthPtr] = 1; + } catch (IndexOutOfBoundsException e) { + int oldStackLength = expressionLengthStack.length; + int[] oldPos = expressionLengthStack; + expressionLengthStack = new int[oldStackLength + ExpressionStackIncrement]; + System.arraycopy(oldPos, 0, expressionLengthStack, 0, oldStackLength); + expressionLengthStack[expressionLengthPtr] = 1; + } +} +protected void pushOnExpressionStackLengthStack(int pos) { + try { + expressionLengthStack[++expressionLengthPtr] = pos; + } catch (IndexOutOfBoundsException e) { + int oldStackLength = expressionLengthStack.length; + int[] oldPos = expressionLengthStack; + expressionLengthStack = new int[oldStackLength + StackIncrement]; + System.arraycopy(oldPos, 0, expressionLengthStack, 0, oldStackLength); + expressionLengthStack[expressionLengthPtr] = pos; + } +} +protected void pushOnIntStack(int pos) { + + try { + intStack[++intPtr] = pos; + } catch (IndexOutOfBoundsException e) { + //intPtr is correct + int oldStackLength = intStack.length; + int oldStack[] = intStack; + intStack = new int[oldStackLength + StackIncrement]; + System.arraycopy(oldStack, 0, intStack, 0, oldStackLength); + intStack[intPtr] = pos; + } +} +protected static char[] readTable(String filename) throws java.io.IOException { + + //files are located at Parser.class directory + + InputStream stream = new BufferedInputStream(Parser.class.getResourceAsStream(filename)); + if (stream == null) { + throw new java.io.IOException(Util.bind("parser.missingFile",filename)); //$NON-NLS-1$ + } + byte[] bytes = null; + try { + bytes = Util.getInputStreamAsByteArray(stream, -1); + } finally { + try { + stream.close(); + } catch (IOException e) { + } + } + + //minimal integrity check (even size expected) + int length = bytes.length; + if (length % 2 != 0) + throw new java.io.IOException(Util.bind("parser.corruptedFile",filename)); //$NON-NLS-1$ + + // convert bytes into chars + char[] chars = new char[length / 2]; + int i = 0; + int charIndex = 0; + + while (true) { + chars[charIndex++] = (char) (((bytes[i++] & 0xFF) << 8) + (bytes[i++] & 0xFF)); + if (i == length) + break; + } + return chars; +} +/* Token check performed on every token shift once having entered + * recovery mode. + */ +public void recoveryTokenCheck() { + switch (currentToken) { + case TokenNameLBRACE : { + RecoveredElement newElement = + currentElement.updateOnOpeningBrace(scanner.currentPosition - 1); + lastCheckPoint = scanner.currentPosition; + if (newElement != null){ // null means nothing happened + restartRecovery = true; // opening brace detected + currentElement = newElement; + } + break; + } + case TokenNameRBRACE : { + endPosition = this.flushAnnotationsDefinedPriorTo(scanner.currentPosition - 1); + RecoveredElement newElement = + currentElement.updateOnClosingBrace(scanner.startPosition, scanner.currentPosition -1); + lastCheckPoint = scanner.currentPosition; + if (newElement != currentElement){ + currentElement = newElement; + } + } + } +} +protected void reportSyntaxError(int act, int currentKind, int stateStackTop) { + + /* remember current scanner position */ + int startPos = scanner.startPosition; + int currentPos = scanner.currentPosition; + + String[] expectings; + String tokenName = name[symbol_index[currentKind]]; + + //fetch all "accurate" possible terminals that could recover the error + int start, end = start = asi(stack[stateStackTop]); + while (asr[end] != 0) + end++; + int length = end - start; + expectings = new String[length]; + if (length != 0) { + char[] indexes = new char[length]; + System.arraycopy(asr, start, indexes, 0, length); + for (int i = 0; i < length; i++) { + expectings[i] = name[symbol_index[indexes[i]]]; + } + } + + //if the pb is an EOF, try to tell the user that they are some + if (tokenName.equals(UNEXPECTED_EOF)) { + if (!this.checkAndReportBracketAnomalies(problemReporter())) { + char[] tokenSource; + try { + tokenSource = this.scanner.getCurrentTokenSource(); + } catch (Exception e) { + tokenSource = new char[] {}; + } + problemReporter().parseError( + this.scanner.startPosition, + this.scanner.currentPosition - 1, + tokenSource, + tokenName, + expectings); + } + } else { //the next test is HEAVILY grammar DEPENDENT. + if ((length == 2) + && (tokenName.equals(";")) //$NON-NLS-1$ + && (expectings[0] == "++") //$NON-NLS-1$ + && (expectings[1] == "--") //$NON-NLS-1$ + && (expressionPtr > -1)) { + // the ; is not the expected token ==> it ends a statement when an expression is not ended + problemReporter().invalidExpressionAsStatement(expressionStack[expressionPtr]); + } else { + char[] tokenSource; + try { + tokenSource = this.scanner.getCurrentTokenSource(); + } catch (Exception e) { + tokenSource = new char[] {}; + } + problemReporter().parseError( + this.scanner.startPosition, + this.scanner.currentPosition - 1, + tokenSource, + tokenName, + expectings); + this.checkAndReportBracketAnomalies(problemReporter()); + } + } + /* reset scanner where it was */ + scanner.startPosition = startPos; + scanner.currentPosition = currentPos; +} +protected void resetModifiers() { + modifiers = AccDefault; + modifiersSourceStart = -1; // <-- see comment into modifiersFlag(int) + scanner.commentPtr = -1; +} +/* + * Reset context so as to resume to regular parse loop + */ +protected void resetStacks() { + + astPtr = -1; + astLengthPtr = -1; + expressionPtr = -1; + expressionLengthPtr = -1; + identifierPtr = -1; + identifierLengthPtr = -1; + intPtr = -1; + nestedMethod[nestedType = 0] = 0; // need to reset for further reuse + variablesCounter[nestedType] = 0; + dimensions = 0 ; + realBlockStack[realBlockPtr = 0] = 0; + recoveredStaticInitializerStart = 0; + listLength = 0; +} +/* + * Reset context so as to resume to regular parse loop + * If unable to reset for resuming, answers false. + * + * Move checkpoint location, reset internal stacks and + * decide which grammar goal is activated. + */ +protected boolean resumeAfterRecovery() { + + // reset internal stacks + this.resetStacks(); + + /* attempt to move checkpoint location */ + if (!this.moveRecoveryCheckpoint()) return false; + + // only look for headers + if (referenceContext instanceof CompilationUnitDeclaration){ + goForHeaders(); + diet = true; // passed this point, will not consider method bodies + return true; + } + // does not know how to restart + return false; +} +/* + * Syntax error was detected. Will attempt to perform some recovery action in order + * to resume to the regular parse loop. + */ +protected boolean resumeOnSyntaxError() { + + /* request recovery initialization */ + if (currentElement == null){ + currentElement = + this.buildInitialRecoveryState(); // build some recovered elements + } + /* do not investigate deeper in recovery when no recovered element */ + if (currentElement == null) return false; + + /* manual forced recovery restart - after headers */ + if (restartRecovery){ + restartRecovery = false; + } + /* update recovery state with current error state of the parser */ + this.updateRecoveryState(); + + /* attempt to reset state in order to resume to parse loop */ + return this.resumeAfterRecovery(); +} +protected static int tAction(int state, int sym) { + return action[check(state + sym) == sym ? state + sym : state]; +} +public String toString() { + + String s = "identifierStack : char[][] = {"; //$NON-NLS-1$ + for (int i = 0; i <= identifierPtr; i++) { + s = s + "\"" + String.valueOf(identifierStack[i]) + "\","; //$NON-NLS-1$ //$NON-NLS-2$ + }; + s = s + "}\n"; //$NON-NLS-1$ + + s = s + "identierLengthStack : int[] = {"; //$NON-NLS-1$ + for (int i = 0; i <= identifierLengthPtr; i++) { + s = s + identifierLengthStack[i] + ","; //$NON-NLS-1$ + }; + s = s + "}\n"; //$NON-NLS-1$ + + s = s + "astLengthStack : int[] = {"; //$NON-NLS-1$ + for (int i = 0; i <= astLengthPtr; i++) { + s = s + astLengthStack[i] + ","; //$NON-NLS-1$ + }; + s = s + "}\n"; //$NON-NLS-1$ + s = s + "astPtr : int = " + String.valueOf(astPtr) + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ + + s = s + "intStack : int[] = {"; //$NON-NLS-1$ + for (int i = 0; i <= intPtr; i++) { + s = s + intStack[i] + ","; //$NON-NLS-1$ + }; + s = s + "}\n"; //$NON-NLS-1$ + + s = s + "expressionLengthStack : int[] = {"; //$NON-NLS-1$ + for (int i = 0; i <= expressionLengthPtr; i++) { + s = s + expressionLengthStack[i] + ","; //$NON-NLS-1$ + }; + s = s + "}\n"; //$NON-NLS-1$ + + s = s + "expressionPtr : int = " + String.valueOf(expressionPtr) + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ + + s = s + "\n\n\n----------------Scanner--------------\n" + scanner.toString(); //$NON-NLS-1$ + return s; + +} +/* + * Update recovery state based on current parser/scanner state + */ +protected void updateRecoveryState() { + + /* expose parser state to recovery state */ + currentElement.updateFromParserState(); + + /* check and update recovered state based on current token, + this action is also performed when shifting token after recovery + got activated once. + */ + this.recoveryTokenCheck(); +} +protected void updateSourceDeclarationParts(int variableDeclaratorsCounter) { + //fields is a definition of fields that are grouped together like in + //public int[] a, b[], c + //which results into 3 fields. + + FieldDeclaration field; + int endTypeDeclarationPosition = + -1 + astStack[astPtr - variableDeclaratorsCounter + 1].sourceStart; + for (int i = 0; i < variableDeclaratorsCounter - 1; i++) { + //last one is special(see below) + field = (FieldDeclaration) astStack[astPtr - i - 1]; + field.endPart1Position = endTypeDeclarationPosition; + field.endPart2Position = -1 + astStack[astPtr - i].sourceStart; + } + //last one + (field = (FieldDeclaration) astStack[astPtr]).endPart1Position = + endTypeDeclarationPosition; + field.endPart2Position = field.declarationSourceEnd; + +} +protected void updateSourcePosition(Expression exp) { + //update the source Position of the expression + + //intStack : int int + //--> + //intStack : + + exp.sourceEnd = intStack[intPtr--]; + exp.sourceStart = intStack[intPtr--]; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/ParserBasicInformation.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/ParserBasicInformation.java new file mode 100644 index 0000000..33d358e --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/ParserBasicInformation.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.parser; + +/*An interface that contains static declarations for some basic information + about the parser such as the number of rules in the grammar, the starting state, etc...*/ + +public interface ParserBasicInformation { + + public final static int + ERROR_SYMBOL = 307, + MAX_NAME_LENGTH = 36, + NUM_STATES = 591, + NT_OFFSET = 308, + SCOPE_UBOUND = -1, + SCOPE_SIZE = 0, + LA_STATE_OFFSET = 16966, + MAX_LA = 1, + NUM_RULES = 436, + NUM_TERMINALS = 105, + NUM_NON_TERMINALS = 203, + NUM_SYMBOLS = 308, + START_STATE = 12260, + EOFT_SYMBOL = 158, + EOLT_SYMBOL = 158, + ACCEPT_ACTION = 16965, + ERROR_ACTION = 16966; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredBlock.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredBlock.java new file mode 100644 index 0000000..8c38f8b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredBlock.java @@ -0,0 +1,343 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.parser; + +/** + * Internal block structure for parsing recovery + */ +import net.sourceforge.phpdt.core.compiler.ITerminalSymbols; +import net.sourceforge.phpdt.internal.compiler.ast.Argument; +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.ast.Block; +import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.LocalDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.Statement; +import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.lookup.BaseTypes; +import net.sourceforge.phpdt.internal.compiler.lookup.CompilerModifiers; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class RecoveredBlock extends RecoveredStatement implements CompilerModifiers, ITerminalSymbols, BaseTypes { + + public Block blockDeclaration; + + public RecoveredStatement[] statements; + public int statementCount; + + public boolean preserveContent = false; + public RecoveredLocalVariable pendingArgument; +public RecoveredBlock(Block block, RecoveredElement parent, int bracketBalance){ + super(block, parent, bracketBalance); + this.blockDeclaration = block; + this.foundOpeningBrace = true; +} +/* + * Record a nested block declaration + */ +public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalance) { + + /* do not consider a nested block starting passed the block end (if set) + it must be belonging to an enclosing block */ + if (blockDeclaration.sourceEnd != 0 + && nestedBlockDeclaration.sourceStart > blockDeclaration.sourceEnd){ + return this.parent.add(nestedBlockDeclaration, bracketBalance); + } + + RecoveredBlock element = new RecoveredBlock(nestedBlockDeclaration, this, bracketBalance); + + // if we have a pending Argument, promote it into the new block + if (pendingArgument != null){ + element.attach(pendingArgument); + pendingArgument = null; + } + this.attach(element); + if (nestedBlockDeclaration.sourceEnd == 0) return element; + return this; +} +/* + * Record a local declaration + */ +public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalance) { + return this.add(localDeclaration, bracketBalance, false); +} +/* + * Record a local declaration + */ +public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalance, boolean delegatedByParent) { + + /* local variables inside method can only be final and non void */ +/* + char[][] localTypeName; + if ((localDeclaration.modifiers & ~AccFinal) != 0 // local var can only be final + || (localDeclaration.type == null) // initializer + || ((localTypeName = localDeclaration.type.getTypeName()).length == 1 // non void + && CharOperation.equals(localTypeName[0], VoidBinding.sourceName()))){ + + if (delegatedByParent){ + return this; //ignore + } else { + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1)); + return this.parent.add(localDeclaration, bracketBalance); + } + } +*/ + /* do not consider a local variable starting passed the block end (if set) + it must be belonging to an enclosing block */ + if (blockDeclaration.sourceEnd != 0 + && localDeclaration.declarationSourceStart > blockDeclaration.sourceEnd){ + + if (delegatedByParent){ + return this; //ignore + } else { + return this.parent.add(localDeclaration, bracketBalance); + } + } + + RecoveredLocalVariable element = new RecoveredLocalVariable(localDeclaration, this, bracketBalance); + + if (localDeclaration instanceof Argument){ + pendingArgument = element; + return this; + } + + this.attach(element); + if (localDeclaration.declarationSourceEnd == 0) return element; + return this; +} +/* + * Record a statement declaration + */ +public RecoveredElement add(Statement statement, int bracketBalance) { + return this.add(statement, bracketBalance, false); +} + +/* + * Record a statement declaration + */ +public RecoveredElement add(Statement statement, int bracketBalance, boolean delegatedByParent) { + + /* do not consider a nested block starting passed the block end (if set) + it must be belonging to an enclosing block */ + if (blockDeclaration.sourceEnd != 0 + && statement.sourceStart > blockDeclaration.sourceEnd){ + + if (delegatedByParent){ + return this; //ignore + } else { + return this.parent.add(statement, bracketBalance); + } + } + + RecoveredStatement element = new RecoveredStatement(statement, this, bracketBalance); + this.attach(element); + if (statement.sourceEnd == 0) return element; + return this; +} +/* + * Addition of a type to an initializer (act like inside method body) + */ +public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalance) { + return this.add(typeDeclaration, bracketBalance, false); +} +/* + * Addition of a type to an initializer (act like inside method body) + */ +public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalance, boolean delegatedByParent) { + + /* do not consider a type starting passed the block end (if set) + it must be belonging to an enclosing block */ + if (blockDeclaration.sourceEnd != 0 + && typeDeclaration.declarationSourceStart > blockDeclaration.sourceEnd){ + if (delegatedByParent){ + return this; //ignore + } else { + return this.parent.add(typeDeclaration, bracketBalance); + } + } + + RecoveredStatement element = new RecoveredType(typeDeclaration, this, bracketBalance); + this.attach(element); + if (typeDeclaration.declarationSourceEnd == 0) return element; + return this; +} +/* + * Attach a recovered statement + */ +void attach(RecoveredStatement recoveredStatement) { + + if (statements == null) { + statements = new RecoveredStatement[5]; + statementCount = 0; + } else { + if (statementCount == statements.length) { + System.arraycopy( + statements, + 0, + (statements = new RecoveredStatement[2 * statementCount]), + 0, + statementCount); + } + } + statements[statementCount++] = recoveredStatement; +} +/* + * Answer the associated parsed structure + */ +public AstNode parseTree(){ + return blockDeclaration; +} +public String toString(int tab) { + StringBuffer result = new StringBuffer(tabString(tab)); + result.append("Recovered block:\n"); //$NON-NLS-1$ + result.append(blockDeclaration.toString(tab + 1)); + if (this.statements != null) { + for (int i = 0; i < this.statementCount; i++) { + result.append("\n"); //$NON-NLS-1$ + result.append(this.statements[i].toString(tab + 1)); + } + } + return result.toString(); +} +/* + * Rebuild a block from the nested structure which is in scope + */ +public Block updatedBlock(){ + + // if block was not marked to be preserved or empty, then ignore it + if (!preserveContent || statementCount == 0) return null; + + Statement[] updatedStatements = new Statement[statementCount]; + int updatedCount = 0; + + // only collect the non-null updated statements + for (int i = 0; i < statementCount; i++){ + Statement updatedStatement = statements[i].updatedStatement(); + if (updatedStatement != null){ + updatedStatements[updatedCount++] = updatedStatement; + } + } + if (updatedCount == 0) return null; // not interesting block + + // resize statement collection if necessary + if (updatedCount != statementCount){ + blockDeclaration.statements = new Statement[updatedCount]; + System.arraycopy(updatedStatements, 0, blockDeclaration.statements, 0, updatedCount); + } else { + blockDeclaration.statements = updatedStatements; + } + + return blockDeclaration; +} +/* + * Rebuild a statement from the nested structure which is in scope + */ +public Statement updatedStatement(){ + + return this.updatedBlock(); +} +/* + * A closing brace got consumed, might have closed the current element, + * in which case both the currentElement is exited + */ +public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){ + if ((--bracketBalance <= 0) && (parent != null)){ + this.updateSourceEndIfNecessary(braceEnd); + + /* if the block is the method body, then it closes the method too */ + RecoveredMethod method = enclosingMethod(); + if (method != null && method.methodBody == this){ + return parent.updateOnClosingBrace(braceStart, braceEnd); + } + RecoveredInitializer initializer = enclosingInitializer(); + if (initializer != null && initializer.initializerBody == this){ + return parent.updateOnClosingBrace(braceStart, braceEnd); + } + return parent; + } + return this; +} +/* + * An opening brace got consumed, might be the expected opening one of the current element, + * in which case the bodyStart is updated. + */ +public RecoveredElement updateOnOpeningBrace(int currentPosition){ + + // create a nested block + Block block = new Block(0); + block.sourceStart = parser().scanner.startPosition; + return this.add(block, 1); +} +/* + * Final update the corresponding parse node + */ +public void updateParseTree(){ + + this.updatedBlock(); +} +/* + * Rebuild a flattened block from the nested structure which is in scope + */ +public Statement updateStatement(){ + + // if block was closed or empty, then ignore it + if (this.blockDeclaration.sourceEnd != 0 || statementCount == 0) return null; + + Statement[] updatedStatements = new Statement[statementCount]; + int updatedCount = 0; + + // only collect the non-null updated statements + for (int i = 0; i < statementCount; i++){ + Statement updatedStatement = statements[i].updatedStatement(); + if (updatedStatement != null){ + updatedStatements[updatedCount++] = updatedStatement; + } + } + if (updatedCount == 0) return null; // not interesting block + + // resize statement collection if necessary + if (updatedCount != statementCount){ + blockDeclaration.statements = new Statement[updatedCount]; + System.arraycopy(updatedStatements, 0, blockDeclaration.statements, 0, updatedCount); + } else { + blockDeclaration.statements = updatedStatements; + } + + return blockDeclaration; +} + +/* + * Record a field declaration + */ +public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalance) { + + /* local variables inside method can only be final and non void */ + char[][] fieldTypeName; + if ((fieldDeclaration.modifiers & ~AccFinal) != 0 // local var can only be final + || (fieldDeclaration.type == null) // initializer + || ((fieldTypeName = fieldDeclaration.type.getTypeName()).length == 1 // non void + && CharOperation.equals(fieldTypeName[0], VoidBinding.sourceName()))){ + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart - 1)); + return this.parent.add(fieldDeclaration, bracketBalance); + } + + /* do not consider a local variable starting passed the block end (if set) + it must be belonging to an enclosing block */ + if (blockDeclaration.sourceEnd != 0 + && fieldDeclaration.declarationSourceStart > blockDeclaration.sourceEnd){ + return this.parent.add(fieldDeclaration, bracketBalance); + } + + // ignore the added field, since indicates a local variable behind recovery point + // which thus got parsed as a field reference. This can happen if restarting after + // having reduced an assistNode to get the following context (see 1GEK7SG) + return this; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredElement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredElement.java new file mode 100644 index 0000000..989e57a --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredElement.java @@ -0,0 +1,322 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.parser; + +/** + * Internal structure for parsing recovery + */ +import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.ast.Block; +import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.ImportReference; +import net.sourceforge.phpdt.internal.compiler.ast.LocalDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.Statement; +import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; + +public class RecoveredElement { + + public RecoveredElement parent; + public int bracketBalance; + public boolean foundOpeningBrace; + protected Parser recoveringParser; +public RecoveredElement(RecoveredElement parent, int bracketBalance){ + this(parent, bracketBalance, null); +} +public RecoveredElement(RecoveredElement parent, int bracketBalance, Parser parser){ + this.parent = parent; + this.bracketBalance = bracketBalance; + this.recoveringParser = parser; +} +/* + * Record a method declaration + */ +public RecoveredElement add(AbstractMethodDeclaration methodDeclaration, int bracketBalance) { + + /* default behavior is to delegate recording to parent if any */ + if (parent == null) { + return this; // ignore + } else { + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(methodDeclaration.declarationSourceStart - 1)); + return this.parent.add(methodDeclaration, bracketBalance); + } +} +/* + * Record a nested block declaration + */ +public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalance) { + + /* default behavior is to delegate recording to parent if any */ + if (parent == null) { + return this; // ignore + } else { + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(nestedBlockDeclaration.sourceStart - 1)); + return this.parent.add(nestedBlockDeclaration, bracketBalance); + } +} +/* + * Record a field declaration + */ +public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalance) { + + /* default behavior is to delegate recording to parent if any */ + if (parent == null) { + return this; // ignore + } else { + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart - 1)); + return this.parent.add(fieldDeclaration, bracketBalance); + } +} +/* + * Record an import reference + */ +public RecoveredElement add(ImportReference importReference, int bracketBalance){ + + /* default behavior is to delegate recording to parent if any */ + if (parent == null) { + return this; // ignore + } else { + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(importReference.declarationSourceStart - 1)); + return this.parent.add(importReference, bracketBalance); + } +} +/* + * Record a local declaration + */ +public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalance) { + + /* default behavior is to delegate recording to parent if any */ + if (parent == null) { + return this; // ignore + } else { + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1)); + return this.parent.add(localDeclaration, bracketBalance); + } +} +/* + * Record a statement + */ +public RecoveredElement add(Statement statement, int bracketBalance) { + + /* default behavior is to delegate recording to parent if any */ + if (parent == null) { + return this; // ignore + } else { + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(statement.sourceStart - 1)); + return this.parent.add(statement, bracketBalance); + } +} +/* + * Record a type declaration + */ +public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalance){ + + /* default behavior is to delegate recording to parent if any */ + if (parent == null) { + return this; // ignore + } else { + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(typeDeclaration.declarationSourceStart - 1)); + return this.parent.add(typeDeclaration, bracketBalance); + } +} +/* + * Answer the depth of this element, considering the parent link. + */ +public int depth(){ + int depth = 0; + RecoveredElement current = this; + while ((current = current.parent) != null) depth++; + return depth; +} +/* + * Answer the enclosing method node, or null if none + */ +public RecoveredInitializer enclosingInitializer(){ + RecoveredElement current = this; + while (current != null){ + if (current instanceof RecoveredInitializer){ + return (RecoveredInitializer) current; + } + current = current.parent; + } + return null; +} +/* + * Answer the enclosing method node, or null if none + */ +public RecoveredMethod enclosingMethod(){ + RecoveredElement current = this; + while (current != null){ + if (current instanceof RecoveredMethod){ + return (RecoveredMethod) current; + } + current = current.parent; + } + return null; +} +/* + * Answer the enclosing type node, or null if none + */ +public RecoveredType enclosingType(){ + RecoveredElement current = this; + while (current != null){ + if (current instanceof RecoveredType){ + return (RecoveredType) current; + } + current = current.parent; + } + return null; +} +/* + * Answer the closest specified parser + */ +public Parser parser(){ + RecoveredElement current = this; + while (current != null){ + if (current.recoveringParser != null){ + return current.recoveringParser; + } + current = current.parent; + } + return null; +} +/* + * Answer the associated parsed structure + */ +public AstNode parseTree(){ + return null; +} +/* + * Iterate the enclosing blocks and tag them so as to preserve their content + */ +public void preserveEnclosingBlocks(){ + RecoveredElement current = this; + while (current != null){ + if (current instanceof RecoveredBlock){ + ((RecoveredBlock)current).preserveContent = true; + } + if (current instanceof RecoveredType){ // for anonymous types + ((RecoveredType)current).preserveContent = true; + } + current = current.parent; + } +} +/* + * Answer the position of the previous line end if + * there is nothing but spaces in between it and the + * line end. Used to trim spaces on unclosed elements. + */ +public int previousAvailableLineEnd(int position){ + + Parser parser = this.parser(); + if (parser == null) return position; + + Scanner scanner = parser.scanner; + if (scanner.lineEnds == null) return position; + + int index = scanner.getLineNumber(position); + if (index < 2) return position; + int previousLineEnd = scanner.lineEnds[index-2]; + + char[] source = scanner.source; + for (int i = previousLineEnd+1; i < position; i++){ + if (!(source[i] == ' ' || source[i] == '\t')) return position; + } + return previousLineEnd; +} +/* + * Answer the very source end of the corresponding parse node + */ +public int sourceEnd(){ + return 0; +} +protected String tabString(int tab) { + StringBuffer result = new StringBuffer(); + for (int i = tab; i > 0; i--) { + result.append(" "); //$NON-NLS-1$ + } + return result.toString(); +} +/* + * Answer the top node + */ +public RecoveredElement topElement(){ + RecoveredElement current = this; + while (current.parent != null){ + current = current.parent; + } + return current; +} +public String toString() { + return toString(0); +} +public String toString(int tab) { + return super.toString(); +} +/* + * Answer the enclosing type node, or null if none + */ +public RecoveredType type(){ + RecoveredElement current = this; + while (current != null){ + if (current instanceof RecoveredType){ + return (RecoveredType) current; + } + current = current.parent; + } + return null; +} +/* + * Update the bodyStart of the corresponding parse node + */ +public void updateBodyStart(int bodyStart){ + this.foundOpeningBrace = true; +} +/* + * Update the corresponding parse node from parser state which + * is about to disappear because of restarting recovery + */ +public void updateFromParserState(){ +} +/* + * A closing brace got consumed, might have closed the current element, + * in which case both the currentElement is exited + */ +public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){ + if ((--bracketBalance <= 0) && (parent != null)){ + this.updateSourceEndIfNecessary(braceEnd); + return parent; + } + return this; +} +/* + * An opening brace got consumed, might be the expected opening one of the current element, + * in which case the bodyStart is updated. + */ +public RecoveredElement updateOnOpeningBrace(int braceEnd){ + + if (bracketBalance++ == 0){ + this.updateBodyStart(braceEnd + 1); + return this; + } + return null; // no update is necessary +} +/* + * Final update the corresponding parse node + */ +public void updateParseTree(){ +} +/* + * Update the declarationSourceEnd of the corresponding parse node + */ +public void updateSourceEndIfNecessary(int sourceEnd){ +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredField.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredField.java new file mode 100644 index 0000000..789cd66 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredField.java @@ -0,0 +1,168 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.parser; + +/** + * Internal field structure for parsing recovery + */ +import net.sourceforge.phpdt.internal.compiler.ast.AnonymousLocalTypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.ArrayTypeReference; +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.ast.Expression; +import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.Statement; +import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; + +public class RecoveredField extends RecoveredElement { + + public FieldDeclaration fieldDeclaration; + boolean alreadyCompletedFieldInitialization; + + public RecoveredType[] anonymousTypes; + public int anonymousTypeCount; +public RecoveredField(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance){ + this(fieldDeclaration, parent, bracketBalance, null); +} +public RecoveredField(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance, Parser parser){ + super(parent, bracketBalance, parser); + this.fieldDeclaration = fieldDeclaration; + this.alreadyCompletedFieldInitialization = fieldDeclaration.initialization != null; +} +/* + * Record an expression statement if field is expecting an initialization expression, + * used for completion inside field initializers. + */ +public RecoveredElement add(Statement statement, int bracketBalance) { + + if (this.alreadyCompletedFieldInitialization || !(statement instanceof Expression)) { + return super.add(statement, bracketBalance); + } else { + this.alreadyCompletedFieldInitialization = true; + this.fieldDeclaration.initialization = (Expression)statement; + this.fieldDeclaration.declarationSourceEnd = statement.sourceEnd; + this.fieldDeclaration.declarationEnd = statement.sourceEnd; + return this; + } +} +/* + * Record a type declaration if this field is expecting an initialization expression + * and the type is an anonymous type. + * Used for completion inside field initializers. + */ +public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalance) { + + if (this.alreadyCompletedFieldInitialization + || !(typeDeclaration instanceof AnonymousLocalTypeDeclaration) + || (this.fieldDeclaration.declarationSourceEnd != 0 && typeDeclaration.sourceStart > this.fieldDeclaration.declarationSourceEnd)) { + return super.add(typeDeclaration, bracketBalance); + } else { + // Prepare anonymous type list + if (this.anonymousTypes == null) { + this.anonymousTypes = new RecoveredType[5]; + this.anonymousTypeCount = 0; + } else { + if (this.anonymousTypeCount == this.anonymousTypes.length) { + System.arraycopy( + this.anonymousTypes, + 0, + (this.anonymousTypes = new RecoveredType[2 * this.anonymousTypeCount]), + 0, + this.anonymousTypeCount); + } + } + // Store type declaration as an anonymous type + RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalance); + this.anonymousTypes[this.anonymousTypeCount++] = element; + return element; + } +} +/* + * Answer the associated parsed structure + */ +public AstNode parseTree(){ + return fieldDeclaration; +} +/* + * Answer the very source end of the corresponding parse node + */ +public int sourceEnd(){ + return this.fieldDeclaration.declarationSourceEnd; +} +public String toString(int tab){ + StringBuffer buffer = new StringBuffer(tabString(tab)); + buffer.append("Recovered field:\n"); //$NON-NLS-1$ + buffer.append(fieldDeclaration.toString(tab + 1)); + if (this.anonymousTypes != null) { + for (int i = 0; i < this.anonymousTypeCount; i++){ + buffer.append("\n"); //$NON-NLS-1$ + buffer.append(anonymousTypes[i].toString(tab + 1)); + } + } + return buffer.toString(); +} +public FieldDeclaration updatedFieldDeclaration(){ + + if (this.anonymousTypes != null && fieldDeclaration.initialization == null) { + for (int i = 0; i < this.anonymousTypeCount; i++){ + if (anonymousTypes[i].preserveContent){ + fieldDeclaration.initialization = + ((AnonymousLocalTypeDeclaration)this.anonymousTypes[i].updatedTypeDeclaration()).allocation; + } + } + if (this.anonymousTypeCount > 0) fieldDeclaration.bits |= AstNode.HasLocalTypeMASK; + } + return fieldDeclaration; +} +/* + * A closing brace got consumed, might have closed the current element, + * in which case both the currentElement is exited. + * + * Fields have no associated braces, thus if matches, then update parent. + */ +public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){ + if (bracketBalance > 0){ // was an array initializer + bracketBalance--; + if (bracketBalance == 0) alreadyCompletedFieldInitialization = true; + return this; + } + if (parent != null){ + return parent.updateOnClosingBrace(braceStart, braceEnd); + } + return this; +} +/* + * An opening brace got consumed, might be the expected opening one of the current element, + * in which case the bodyStart is updated. + */ +public RecoveredElement updateOnOpeningBrace(int currentPosition){ + if (fieldDeclaration.declarationSourceEnd == 0 + && fieldDeclaration.type instanceof ArrayTypeReference + && !alreadyCompletedFieldInitialization){ + bracketBalance++; + return null; // no update is necessary (array initializer) + } + // might be an array initializer + this.updateSourceEndIfNecessary(currentPosition - 1); + return this.parent.updateOnOpeningBrace(currentPosition); +} +public void updateParseTree(){ + this.updatedFieldDeclaration(); +} +/* + * Update the declarationSourceEnd of the corresponding parse node + */ +public void updateSourceEndIfNecessary(int sourceEnd){ + if (this.fieldDeclaration.declarationSourceEnd == 0) { + this.fieldDeclaration.declarationSourceEnd = sourceEnd; + this.fieldDeclaration.declarationEnd = sourceEnd; + } +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredImport.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredImport.java new file mode 100644 index 0000000..56a31b5 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredImport.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.parser; + +/** + * Internal import structure for parsing recovery + */ +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.ast.ImportReference; + +public class RecoveredImport extends RecoveredElement { + + public ImportReference importReference; +public RecoveredImport(ImportReference importReference, RecoveredElement parent, int bracketBalance){ + super(parent, bracketBalance); + this.importReference = importReference; +} +/* + * Answer the associated parsed structure + */ +public AstNode parseTree(){ + return importReference; +} +/* + * Answer the very source end of the corresponding parse node + */ +public int sourceEnd(){ + return this.importReference.declarationSourceEnd; +} +public String toString(int tab) { + return tabString(tab) + "Recovered import: " + importReference.toString(); //$NON-NLS-1$ +} +public ImportReference updatedImportReference(){ + + return importReference; +} +public void updateParseTree(){ + this.updatedImportReference(); +} +/* + * Update the declarationSourceEnd of the corresponding parse node + */ +public void updateSourceEndIfNecessary(int sourceEnd){ + if (this.importReference.declarationSourceEnd == 0) { + this.importReference.declarationSourceEnd = sourceEnd; + this.importReference.declarationEnd = sourceEnd; + } +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredInitializer.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredInitializer.java new file mode 100644 index 0000000..f56dc11 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredInitializer.java @@ -0,0 +1,243 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.parser; + +/** + * Internal initializer structure for parsing recovery + */ +import net.sourceforge.phpdt.core.compiler.ITerminalSymbols; +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.ast.Block; +import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.Initializer; +import net.sourceforge.phpdt.internal.compiler.ast.LocalDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.LocalTypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.Statement; +import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.lookup.BaseTypes; +import net.sourceforge.phpdt.internal.compiler.lookup.CompilerModifiers; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class RecoveredInitializer extends RecoveredField implements CompilerModifiers, ITerminalSymbols, BaseTypes { + + public RecoveredType[] localTypes; + public int localTypeCount; + + public RecoveredBlock initializerBody; +public RecoveredInitializer(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance){ + this(fieldDeclaration, parent, bracketBalance, null); +} +public RecoveredInitializer(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance, Parser parser){ + super(fieldDeclaration, parent, bracketBalance, parser); + this.foundOpeningBrace = true; +} +/* + * Record a nested block declaration + */ +public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalance) { + + /* default behavior is to delegate recording to parent if any, + do not consider elements passed the known end (if set) + it must be belonging to an enclosing element + */ + if (fieldDeclaration.declarationSourceEnd > 0 + && nestedBlockDeclaration.sourceStart + > fieldDeclaration.declarationSourceEnd){ + if (this.parent == null){ + return this; // ignore + } else { + return this.parent.add(nestedBlockDeclaration, bracketBalance); + } + } + /* consider that if the opening brace was not found, it is there */ + if (!foundOpeningBrace){ + foundOpeningBrace = true; + this.bracketBalance++; + } + + initializerBody = new RecoveredBlock(nestedBlockDeclaration, this, bracketBalance); + if (nestedBlockDeclaration.sourceEnd == 0) return initializerBody; + return this; +} +/* + * Record a field declaration (act like inside method body) + */ +public RecoveredElement add(FieldDeclaration newFieldDeclaration, int bracketBalance) { + + /* local variables inside initializer can only be final and non void */ + char[][] fieldTypeName; + if ((newFieldDeclaration.modifiers & ~AccFinal) != 0 /* local var can only be final */ + || (newFieldDeclaration.type == null) // initializer + || ((fieldTypeName = newFieldDeclaration.type.getTypeName()).length == 1 // non void + && CharOperation.equals(fieldTypeName[0], VoidBinding.sourceName()))){ + if (this.parent == null) { + return this; // ignore + } else { + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(newFieldDeclaration.declarationSourceStart - 1)); + return this.parent.add(newFieldDeclaration, bracketBalance); + } + } + + /* default behavior is to delegate recording to parent if any, + do not consider elements passed the known end (if set) + it must be belonging to an enclosing element + */ + if (this.fieldDeclaration.declarationSourceEnd > 0 + && newFieldDeclaration.declarationSourceStart + > this.fieldDeclaration.declarationSourceEnd){ + if (this.parent == null) { + return this; // ignore + } else { + return this.parent.add(newFieldDeclaration, bracketBalance); + } + } + // still inside initializer, treat as local variable + return this; // ignore +} +/* + * Record a local declaration - regular method should have been created a block body + */ +public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalance) { + + /* do not consider a type starting passed the type end (if set) + it must be belonging to an enclosing type */ + if (fieldDeclaration.declarationSourceEnd != 0 + && localDeclaration.declarationSourceStart > fieldDeclaration.declarationSourceEnd){ + if (parent == null) { + return this; // ignore + } else { + return this.parent.add(localDeclaration, bracketBalance); + } + } + /* method body should have been created */ + Block block = new Block(0); + block.sourceStart = ((Initializer)fieldDeclaration).bodyStart; + RecoveredElement element = this.add(block, 1); + return element.add(localDeclaration, bracketBalance); +} +/* + * Record a statement - regular method should have been created a block body + */ +public RecoveredElement add(Statement statement, int bracketBalance) { + + /* do not consider a statement starting passed the initializer end (if set) + it must be belonging to an enclosing type */ + if (fieldDeclaration.declarationSourceEnd != 0 + && statement.sourceStart > fieldDeclaration.declarationSourceEnd){ + if (parent == null) { + return this; // ignore + } else { + return this.parent.add(statement, bracketBalance); + } + } + /* initializer body should have been created */ + Block block = new Block(0); + block.sourceStart = ((Initializer)fieldDeclaration).bodyStart; + RecoveredElement element = this.add(block, 1); + return element.add(statement, bracketBalance); +} +public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalance) { + + /* do not consider a type starting passed the type end (if set) + it must be belonging to an enclosing type */ + if (fieldDeclaration.declarationSourceEnd != 0 + && typeDeclaration.declarationSourceStart > fieldDeclaration.declarationSourceEnd){ + if (parent == null) { + return this; // ignore + } else { + return this.parent.add(typeDeclaration, bracketBalance); + } + } + if (typeDeclaration instanceof LocalTypeDeclaration){ + /* method body should have been created */ + Block block = new Block(0); + block.sourceStart = ((Initializer)fieldDeclaration).bodyStart; + RecoveredElement element = this.add(block, 1); + return element.add(typeDeclaration, bracketBalance); + } + if (localTypes == null) { + localTypes = new RecoveredType[5]; + localTypeCount = 0; + } else { + if (localTypeCount == localTypes.length) { + System.arraycopy( + localTypes, + 0, + (localTypes = new RecoveredType[2 * localTypeCount]), + 0, + localTypeCount); + } + } + RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalance); + localTypes[localTypeCount++] = element; + + /* consider that if the opening brace was not found, it is there */ + if (!foundOpeningBrace){ + foundOpeningBrace = true; + this.bracketBalance++; + } + return element; +} +public String toString(int tab) { + StringBuffer result = new StringBuffer(tabString(tab)); + result.append("Recovered initializer:\n"); //$NON-NLS-1$ + result.append(this.fieldDeclaration.toString(tab + 1)); + if (this.initializerBody != null) { + result.append("\n"); //$NON-NLS-1$ + result.append(this.initializerBody.toString(tab + 1)); + } + return result.toString(); +} +public FieldDeclaration updatedFieldDeclaration(){ + + if (initializerBody != null){ + Block block = initializerBody.updatedBlock(); + if (block != null){ + ((Initializer)fieldDeclaration).block = block; + } + if (this.localTypeCount > 0) fieldDeclaration.bits |= AstNode.HasLocalTypeMASK; + + } + if (fieldDeclaration.sourceEnd == 0){ + fieldDeclaration.sourceEnd = fieldDeclaration.declarationSourceEnd; + } + return fieldDeclaration; +} +/* + * A closing brace got consumed, might have closed the current element, + * in which case both the currentElement is exited + */ +public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){ + if ((--bracketBalance <= 0) && (parent != null)){ + this.updateSourceEndIfNecessary(braceEnd); + return parent; + } + return this; +} +/* + * An opening brace got consumed, might be the expected opening one of the current element, + * in which case the bodyStart is updated. + */ +public RecoveredElement updateOnOpeningBrace(int currentPosition){ + bracketBalance++; + return this; // request to restart +} +/* + * Update the declarationSourceEnd of the corresponding parse node + */ +public void updateSourceEndIfNecessary(int sourceEnd){ + if (this.fieldDeclaration.declarationSourceEnd == 0) { + this.fieldDeclaration.sourceEnd = sourceEnd; + this.fieldDeclaration.declarationSourceEnd = sourceEnd; + this.fieldDeclaration.declarationEnd = sourceEnd; + } +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredLocalVariable.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredLocalVariable.java new file mode 100644 index 0000000..0b607e8 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredLocalVariable.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.parser; + +/** + * Internal local variable structure for parsing recovery + */ +import net.sourceforge.phpdt.internal.compiler.ast.ArrayTypeReference; +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.ast.LocalDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.Statement; + +public class RecoveredLocalVariable extends RecoveredStatement { + + public LocalDeclaration localDeclaration; + boolean alreadyCompletedLocalInitialization; +public RecoveredLocalVariable(LocalDeclaration localDeclaration, RecoveredElement parent, int bracketBalance){ + super(localDeclaration, parent, bracketBalance); + this.localDeclaration = localDeclaration; + this.alreadyCompletedLocalInitialization = localDeclaration.initialization != null; +} +/* + * Answer the associated parsed structure + */ +public AstNode parseTree(){ + return localDeclaration; +} +/* + * Answer the very source end of the corresponding parse node + */ +public int sourceEnd(){ + return this.localDeclaration.declarationSourceEnd; +} +public String toString(int tab) { + return tabString(tab) + "Recovered local variable:\n" + localDeclaration.toString(tab + 1); //$NON-NLS-1$ +} +public Statement updatedStatement(){ + return localDeclaration; +} +/* + * A closing brace got consumed, might have closed the current element, + * in which case both the currentElement is exited. + * + * Fields have no associated braces, thus if matches, then update parent. + */ +public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){ + if (bracketBalance > 0){ // was an array initializer + bracketBalance--; + if (bracketBalance == 0) alreadyCompletedLocalInitialization = true; + return this; + } + if (parent != null){ + return parent.updateOnClosingBrace(braceStart, braceEnd); + } + return this; +} +/* + * An opening brace got consumed, might be the expected opening one of the current element, + * in which case the bodyStart is updated. + */ +public RecoveredElement updateOnOpeningBrace(int currentPosition){ + if (localDeclaration.declarationSourceEnd == 0 + && localDeclaration.type instanceof ArrayTypeReference + && !alreadyCompletedLocalInitialization){ + bracketBalance++; + return null; // no update is necessary (array initializer) + } + // might be an array initializer + this.updateSourceEndIfNecessary(currentPosition - 1); + return this.parent.updateOnOpeningBrace(currentPosition); +} +public void updateParseTree(){ + this.updatedStatement(); +} +/* + * Update the declarationSourceEnd of the corresponding parse node + */ +public void updateSourceEndIfNecessary(int sourceEnd){ + if (this.localDeclaration.declarationSourceEnd == 0) { + this.localDeclaration.declarationSourceEnd = sourceEnd; + this.localDeclaration.declarationEnd = sourceEnd; + } +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredMethod.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredMethod.java new file mode 100644 index 0000000..d936a92 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredMethod.java @@ -0,0 +1,437 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.parser; + +import net.sourceforge.phpdt.core.compiler.ITerminalSymbols; +import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.Argument; +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.ast.Block; +import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.ExplicitConstructorCall; +import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.LocalDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.LocalTypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.Statement; +import net.sourceforge.phpdt.internal.compiler.ast.SuperReference; +import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.TypeReference; +import net.sourceforge.phpdt.internal.compiler.lookup.BaseTypes; +import net.sourceforge.phpdt.internal.compiler.lookup.CompilerModifiers; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +/** + * Internal method structure for parsing recovery + */ + +public class RecoveredMethod extends RecoveredElement implements CompilerModifiers, ITerminalSymbols, BaseTypes { + + public AbstractMethodDeclaration methodDeclaration; + + public RecoveredType[] localTypes; + public int localTypeCount; + + public RecoveredBlock methodBody; + public boolean discardBody = true; + +public RecoveredMethod(AbstractMethodDeclaration methodDeclaration, RecoveredElement parent, int bracketBalance, Parser parser){ + super(parent, bracketBalance, parser); + this.methodDeclaration = methodDeclaration; + this.foundOpeningBrace = !bodyStartsAtHeaderEnd(); + if(this.foundOpeningBrace) { + this.bracketBalance++; + } +} +/* + * Record a nested block declaration + */ +public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalance) { + + /* default behavior is to delegate recording to parent if any, + do not consider elements passed the known end (if set) + it must be belonging to an enclosing element + */ + if (methodDeclaration.declarationSourceEnd > 0 + && nestedBlockDeclaration.sourceStart + > methodDeclaration.declarationSourceEnd){ + if (this.parent == null){ + return this; // ignore + } else { + return this.parent.add(nestedBlockDeclaration, bracketBalance); + } + } + /* consider that if the opening brace was not found, it is there */ + if (!foundOpeningBrace){ + foundOpeningBrace = true; + this.bracketBalance++; + } + + methodBody = new RecoveredBlock(nestedBlockDeclaration, this, bracketBalance); + if (nestedBlockDeclaration.sourceEnd == 0) return methodBody; + return this; +} +/* + * Record a field declaration + */ +public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalance) { + + /* local variables inside method can only be final and non void */ + char[][] fieldTypeName; + if ((fieldDeclaration.modifiers & ~AccFinal) != 0 // local var can only be final + || (fieldDeclaration.type == null) // initializer + || ((fieldTypeName = fieldDeclaration.type.getTypeName()).length == 1 // non void + && CharOperation.equals(fieldTypeName[0], VoidBinding.sourceName()))){ + + if (this.parent == null){ + return this; // ignore + } else { + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart - 1)); + return this.parent.add(fieldDeclaration, bracketBalance); + } + } + /* default behavior is to delegate recording to parent if any, + do not consider elements passed the known end (if set) + it must be belonging to an enclosing element + */ + if (methodDeclaration.declarationSourceEnd > 0 + && fieldDeclaration.declarationSourceStart + > methodDeclaration.declarationSourceEnd){ + if (this.parent == null){ + return this; // ignore + } else { + return this.parent.add(fieldDeclaration, bracketBalance); + } + } + /* consider that if the opening brace was not found, it is there */ + if (!foundOpeningBrace){ + foundOpeningBrace = true; + this.bracketBalance++; + } + // still inside method, treat as local variable + return this; // ignore +} +/* + * Record a local declaration - regular method should have been created a block body + */ +public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalance) { + + /* local variables inside method can only be final and non void */ +/* + char[][] localTypeName; + if ((localDeclaration.modifiers & ~AccFinal) != 0 // local var can only be final + || (localDeclaration.type == null) // initializer + || ((localTypeName = localDeclaration.type.getTypeName()).length == 1 // non void + && CharOperation.equals(localTypeName[0], VoidBinding.sourceName()))){ + + if (this.parent == null){ + return this; // ignore + } else { + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1)); + return this.parent.add(localDeclaration, bracketBalance); + } + } +*/ + /* do not consider a type starting passed the type end (if set) + it must be belonging to an enclosing type */ + if (methodDeclaration.declarationSourceEnd != 0 + && localDeclaration.declarationSourceStart > methodDeclaration.declarationSourceEnd){ + + if (this.parent == null) { + return this; // ignore + } else { + return this.parent.add(localDeclaration, bracketBalance); + } + } + if (methodBody == null){ + Block block = new Block(0); + block.sourceStart = methodDeclaration.bodyStart; + RecoveredElement currentBlock = this.add(block, 1); + if (this.bracketBalance > 0){ + for (int i = 0; i < this.bracketBalance - 1; i++){ + currentBlock = currentBlock.add(new Block(0), 1); + } + this.bracketBalance = 1; + } + return currentBlock.add(localDeclaration, bracketBalance); + } + return methodBody.add(localDeclaration, bracketBalance, true); +} +/* + * Record a statement - regular method should have been created a block body + */ +public RecoveredElement add(Statement statement, int bracketBalance) { + + /* do not consider a type starting passed the type end (if set) + it must be belonging to an enclosing type */ + if (methodDeclaration.declarationSourceEnd != 0 + && statement.sourceStart > methodDeclaration.declarationSourceEnd){ + + if (this.parent == null) { + return this; // ignore + } else { + return this.parent.add(statement, bracketBalance); + } + } + if (methodBody == null){ + Block block = new Block(0); + block.sourceStart = methodDeclaration.bodyStart; + RecoveredElement currentBlock = this.add(block, 1); + if (this.bracketBalance > 0){ + for (int i = 0; i < this.bracketBalance - 1; i++){ + currentBlock = currentBlock.add(new Block(0), 1); + } + this.bracketBalance = 1; + } + return currentBlock.add(statement, bracketBalance); + } + return methodBody.add(statement, bracketBalance, true); +} +public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalance) { + + /* do not consider a type starting passed the type end (if set) + it must be belonging to an enclosing type */ + if (methodDeclaration.declarationSourceEnd != 0 + && typeDeclaration.declarationSourceStart > methodDeclaration.declarationSourceEnd){ + + if (this.parent == null) { + return this; // ignore + } else { + return this.parent.add(typeDeclaration, bracketBalance); + } + } + if (typeDeclaration instanceof LocalTypeDeclaration){ + if (methodBody == null){ + Block block = new Block(0); + block.sourceStart = methodDeclaration.bodyStart; + this.add(block, 1); + } + return methodBody.add(typeDeclaration, bracketBalance, true); + } + if (localTypes == null) { + localTypes = new RecoveredType[5]; + localTypeCount = 0; + } else { + if (localTypeCount == localTypes.length) { + System.arraycopy( + localTypes, + 0, + (localTypes = new RecoveredType[2 * localTypeCount]), + 0, + localTypeCount); + } + } + RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalance); + localTypes[localTypeCount++] = element; + + /* consider that if the opening brace was not found, it is there */ + if (!foundOpeningBrace){ + foundOpeningBrace = true; + this.bracketBalance++; + } + return element; +} +public boolean bodyStartsAtHeaderEnd(){ + return methodDeclaration.bodyStart == methodDeclaration.sourceEnd+1; +} +/* + * Answer the associated parsed structure + */ +public AstNode parseTree(){ + return methodDeclaration; +} +/* + * Answer the very source end of the corresponding parse node + */ +public int sourceEnd(){ + return this.methodDeclaration.declarationSourceEnd; +} +public String toString(int tab) { + StringBuffer result = new StringBuffer(tabString(tab)); + result.append("Recovered method:\n"); //$NON-NLS-1$ + result.append(this.methodDeclaration.toString(tab + 1)); + if (this.localTypes != null) { + for (int i = 0; i < this.localTypeCount; i++) { + result.append("\n"); //$NON-NLS-1$ + result.append(this.localTypes[i].toString(tab + 1)); + } + } + if (this.methodBody != null) { + result.append("\n"); //$NON-NLS-1$ + result.append(this.methodBody.toString(tab + 1)); + } + return result.toString(); +} +/* + * Update the bodyStart of the corresponding parse node + */ +public void updateBodyStart(int bodyStart){ + this.foundOpeningBrace = true; + this.methodDeclaration.bodyStart = bodyStart; +} +public AbstractMethodDeclaration updatedMethodDeclaration(){ + + if (methodBody != null){ + Block block = methodBody.updatedBlock(); + if (block != null){ + methodDeclaration.statements = block.statements; + + /* first statement might be an explict constructor call destinated to a special slot */ + if (methodDeclaration.isConstructor()) { + ConstructorDeclaration constructor = (ConstructorDeclaration)methodDeclaration; + if (methodDeclaration.statements != null + && methodDeclaration.statements[0] instanceof ExplicitConstructorCall){ + constructor.constructorCall = (ExplicitConstructorCall)methodDeclaration.statements[0]; + int length = methodDeclaration.statements.length; + System.arraycopy( + methodDeclaration.statements, + 1, + (methodDeclaration.statements = new Statement[length-1]), + 0, + length-1); + } + if (constructor.constructorCall == null){ // add implicit constructor call + constructor.constructorCall = SuperReference.implicitSuperConstructorCall(); + } + } + } + } + if (localTypeCount > 0) methodDeclaration.bits |= AstNode.HasLocalTypeMASK; + return methodDeclaration; +} +/* + * Update the corresponding parse node from parser state which + * is about to disappear because of restarting recovery + */ +public void updateFromParserState(){ + + if(this.bodyStartsAtHeaderEnd()){ + Parser parser = this.parser(); + /* might want to recover arguments or thrown exceptions */ + if (parser.listLength > 0 && parser.astLengthPtr > 0){ // awaiting interface type references + /* has consumed the arguments - listed elements must be thrown exceptions */ + if (methodDeclaration.sourceEnd == parser.rParenPos) { + + // protection for bugs 15142 + int length = parser.astLengthStack[parser.astLengthPtr]; + int astPtr = parser.astPtr - length; + boolean canConsume = astPtr >= 0; + if(canConsume) { + if((!(parser.astStack[astPtr] instanceof AbstractMethodDeclaration))) { + canConsume = false; + } + for (int i = 1, max = length + 1; i < max; i++) { + if(!(parser.astStack[astPtr + i ] instanceof TypeReference)) { + canConsume = false; + } + } + } + if (canConsume){ + parser.consumeMethodHeaderThrowsClause(); + // will reset typeListLength to zero + // thus this check will only be performed on first errorCheck after void foo() throws X, Y, + } else { + parser.listLength = 0; + } + } else { + /* has not consumed arguments yet, listed elements must be arguments */ + if (parser.currentToken == TokenNameLPAREN || parser.currentToken == TokenNameSEMICOLON){ + /* if currentToken is parenthesis this last argument is a method/field signature */ + parser.astLengthStack[parser.astLengthPtr] --; + parser.astPtr --; + parser.listLength --; + parser.currentToken = 0; + } + int argLength = parser.astLengthStack[parser.astLengthPtr]; + int argStart = parser.astPtr - argLength + 1; + boolean needUpdateRParenPos = parser.rParenPos < parser.lParenPos; // 12387 : rParenPos will be used + // to compute bodyStart, and thus used to set next checkpoint. + int count; + for (count = 0; count < argLength; count++){ + Argument argument = (Argument)parser.astStack[argStart+count]; + /* cannot be an argument if non final */ + char[][] argTypeName = argument.type.getTypeName(); + if ((argument.modifiers & ~AccFinal) != 0 + || (argTypeName.length == 1 + && CharOperation.equals(argTypeName[0], VoidBinding.sourceName()))){ + parser.astLengthStack[parser.astLengthPtr] = count; + parser.astPtr = argStart+count-1; + parser.listLength = count; + parser.currentToken = 0; + break; + } + if (needUpdateRParenPos) parser.rParenPos = argument.sourceEnd + 1; + } + if (parser.listLength > 0 && parser.astLengthPtr > 0){ + + // protection for bugs 15142 + int length = parser.astLengthStack[parser.astLengthPtr]; + int astPtr = parser.astPtr - length; + boolean canConsume = astPtr >= 0; + if(canConsume) { + if((!(parser.astStack[astPtr] instanceof AbstractMethodDeclaration))) { + canConsume = false; + } + for (int i = 1, max = length + 1; i < max; i++) { + if(!(parser.astStack[astPtr + i ] instanceof Argument)) { + canConsume = false; + } + } + } + if(canConsume) { + parser.consumeMethodHeaderParameters(); + /* fix-up positions, given they were updated against rParenPos, which did not get set */ + if (parser.currentElement == this){ // parameter addition might have added an awaiting (no return type) method - see 1FVXQZ4 */ + methodDeclaration.sourceEnd = methodDeclaration.arguments[methodDeclaration.arguments.length-1].sourceEnd; + methodDeclaration.bodyStart = methodDeclaration.sourceEnd+1; + parser.lastCheckPoint = methodDeclaration.bodyStart; + } + } + } + } + } + } +} +/* + * An opening brace got consumed, might be the expected opening one of the current element, + * in which case the bodyStart is updated. + */ +public RecoveredElement updateOnOpeningBrace(int braceEnd){ + + /* in case the opening brace is close enough to the signature */ + if (bracketBalance == 0){ + /* + if (parser.scanner.searchLineNumber(methodDeclaration.sourceEnd) + != parser.scanner.searchLineNumber(braceEnd)){ + */ + switch(parser().lastIgnoredToken){ + case -1 : +// case TokenNamethrows : +// break; + default: + this.foundOpeningBrace = true; + bracketBalance = 1; // pretend the brace was already there + } + } + return super.updateOnOpeningBrace(braceEnd); +} +public void updateParseTree(){ + this.updatedMethodDeclaration(); +} +/* + * Update the declarationSourceEnd of the corresponding parse node + */ +public void updateSourceEndIfNecessary(int sourceEnd){ + if (this.methodDeclaration.declarationSourceEnd == 0) { + this.methodDeclaration.declarationSourceEnd = sourceEnd; + this.methodDeclaration.bodyEnd = sourceEnd; + } +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredStatement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredStatement.java new file mode 100644 index 0000000..9349f01 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredStatement.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.parser; + +/** + * Internal statement structure for parsing recovery + */ +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.ast.Statement; + +public class RecoveredStatement extends RecoveredElement { + + public Statement statement; + boolean alreadyCompletedLocalInitialization; +public RecoveredStatement(Statement statement, RecoveredElement parent, int bracketBalance){ + super(parent, bracketBalance); + this.statement = statement; +} +/* + * Answer the associated parsed structure + */ +public AstNode parseTree(){ + return statement; +} +/* + * Answer the very source end of the corresponding parse node + */ +public int sourceEnd(){ + return this.statement.sourceEnd; +} +public String toString(int tab){ + return tabString(tab) + "Recovered statement:\n" + statement.toString(tab + 1); //$NON-NLS-1$ +} +public Statement updatedStatement(){ + return statement; +} +public void updateParseTree(){ + this.updatedStatement(); +} +/* + * Update the declarationSourceEnd of the corresponding parse node + */ +public void updateSourceEndIfNecessary(int sourceEnd){ + if (this.statement.sourceEnd == 0) + this.statement.sourceEnd = sourceEnd; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredType.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredType.java new file mode 100644 index 0000000..1dddbcd --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredType.java @@ -0,0 +1,505 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.parser; + +import net.sourceforge.phpdt.core.compiler.ITerminalSymbols; +import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.AnonymousLocalTypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.ast.Block; +import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.Initializer; +import net.sourceforge.phpdt.internal.compiler.ast.LocalTypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.MemberTypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.Statement; +import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.TypeReference; +import net.sourceforge.phpdt.internal.compiler.lookup.CompilerModifiers; + +/** + * Internal type structure for parsing recovery + */ + +public class RecoveredType extends RecoveredStatement implements ITerminalSymbols, CompilerModifiers { + public TypeDeclaration typeDeclaration; + + public RecoveredType[] memberTypes; + public int memberTypeCount; + public RecoveredField[] fields; + public int fieldCount; + public RecoveredMethod[] methods; + public int methodCount; + + public boolean preserveContent = false; // only used for anonymous types + public int bodyEnd; + +public RecoveredType(TypeDeclaration typeDeclaration, RecoveredElement parent, int bracketBalance){ + super(typeDeclaration, parent, bracketBalance); + this.typeDeclaration = typeDeclaration; + this.foundOpeningBrace = !bodyStartsAtHeaderEnd(); + if(this.foundOpeningBrace) { + this.bracketBalance++; + } +} +public RecoveredElement add(AbstractMethodDeclaration methodDeclaration, int bracketBalance) { + + /* do not consider a method starting passed the type end (if set) + it must be belonging to an enclosing type */ + if (typeDeclaration.declarationSourceEnd != 0 + && methodDeclaration.declarationSourceStart > typeDeclaration.declarationSourceEnd){ + return this.parent.add(methodDeclaration, bracketBalance); + } + + if (methods == null) { + methods = new RecoveredMethod[5]; + methodCount = 0; + } else { + if (methodCount == methods.length) { + System.arraycopy( + methods, + 0, + (methods = new RecoveredMethod[2 * methodCount]), + 0, + methodCount); + } + } + RecoveredMethod element = new RecoveredMethod(methodDeclaration, this, bracketBalance, this.recoveringParser); + methods[methodCount++] = element; + + /* consider that if the opening brace was not found, it is there */ + if (!foundOpeningBrace){ + foundOpeningBrace = true; + this.bracketBalance++; + } + /* if method not finished, then method becomes current */ + if (methodDeclaration.declarationSourceEnd == 0) return element; + return this; +} +public RecoveredElement add(Block nestedBlockDeclaration,int bracketBalance) { + int modifiers = AccDefault; + if(this.parser().recoveredStaticInitializerStart != 0) { + modifiers = AccStatic; + } + return this.add(new Initializer(nestedBlockDeclaration, modifiers), bracketBalance); +} +public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalance) { + + /* do not consider a field starting passed the type end (if set) + it must be belonging to an enclosing type */ + if (typeDeclaration.declarationSourceEnd != 0 + && fieldDeclaration.declarationSourceStart > typeDeclaration.declarationSourceEnd) { + return this.parent.add(fieldDeclaration, bracketBalance); + } + if (fields == null) { + fields = new RecoveredField[5]; + fieldCount = 0; + } else { + if (fieldCount == fields.length) { + System.arraycopy( + fields, + 0, + (fields = new RecoveredField[2 * fieldCount]), + 0, + fieldCount); + } + } + RecoveredField element = fieldDeclaration.isField() + ? new RecoveredField(fieldDeclaration, this, bracketBalance) + : new RecoveredInitializer(fieldDeclaration, this, bracketBalance); + fields[fieldCount++] = element; + + /* consider that if the opening brace was not found, it is there */ + if (!foundOpeningBrace){ + foundOpeningBrace = true; + this.bracketBalance++; + } + /* if field not finished, then field becomes current */ + if (fieldDeclaration.declarationSourceEnd == 0) return element; + return this; +} +public RecoveredElement add(TypeDeclaration memberTypeDeclaration, int bracketBalance) { + + /* do not consider a type starting passed the type end (if set) + it must be belonging to an enclosing type */ + if (typeDeclaration.declarationSourceEnd != 0 + && memberTypeDeclaration.declarationSourceStart > typeDeclaration.declarationSourceEnd){ + return this.parent.add(memberTypeDeclaration, bracketBalance); + } + + if (memberTypeDeclaration instanceof AnonymousLocalTypeDeclaration){ + if (this.methodCount > 0) { + // add it to the last method body + RecoveredMethod lastMethod = this.methods[this.methodCount-1]; + lastMethod.methodDeclaration.bodyEnd = 0; // reopen method + lastMethod.methodDeclaration.declarationSourceEnd = 0; // reopen method + lastMethod.bracketBalance++; // expect one closing brace + return lastMethod.add(typeDeclaration, bracketBalance); + } else { + // ignore + return this; + } + } + + if (memberTypes == null) { + memberTypes = new RecoveredType[5]; + memberTypeCount = 0; + } else { + if (memberTypeCount == memberTypes.length) { + System.arraycopy( + memberTypes, + 0, + (memberTypes = new RecoveredType[2 * memberTypeCount]), + 0, + memberTypeCount); + } + } + RecoveredType element = new RecoveredType(memberTypeDeclaration, this, bracketBalance); + memberTypes[memberTypeCount++] = element; + + /* consider that if the opening brace was not found, it is there */ + if (!foundOpeningBrace){ + foundOpeningBrace = true; + this.bracketBalance++; + } + /* if member type not finished, then member type becomes current */ + if (memberTypeDeclaration.declarationSourceEnd == 0) return element; + return this; +} +/* + * Answer the body end of the corresponding parse node + */ +public int bodyEnd(){ + if (bodyEnd == 0) return typeDeclaration.declarationSourceEnd; + return bodyEnd; +} +public boolean bodyStartsAtHeaderEnd(){ + if (typeDeclaration.superInterfaces == null){ + if (typeDeclaration.superclass == null){ + return typeDeclaration.bodyStart == typeDeclaration.sourceEnd+1; + } else { + return typeDeclaration.bodyStart == typeDeclaration.superclass.sourceEnd+1; + } + } else { + return typeDeclaration.bodyStart + == typeDeclaration.superInterfaces[typeDeclaration.superInterfaces.length-1].sourceEnd+1; + } +} +/* + * Answer the enclosing type node, or null if none + */ +public RecoveredType enclosingType(){ + RecoveredElement current = parent; + while (current != null){ + if (current instanceof RecoveredType){ + return (RecoveredType) current; + } + current = current.parent; + } + return null; +} +public char[] name(){ + return typeDeclaration.name; +} +/* + * Answer the associated parsed structure + */ +public AstNode parseTree(){ + return typeDeclaration; +} +/* + * Answer the very source end of the corresponding parse node + */ +public int sourceEnd(){ + return this.typeDeclaration.declarationSourceEnd; +} +public String toString(int tab) { + StringBuffer result = new StringBuffer(tabString(tab)); + result.append("Recovered type:\n"); //$NON-NLS-1$ + if (typeDeclaration instanceof AnonymousLocalTypeDeclaration) { + result.append(tabString(tab)); + result.append(" "); //$NON-NLS-1$ + } + result.append(typeDeclaration.toString(tab + 1)); + if (this.memberTypes != null) { + for (int i = 0; i < this.memberTypeCount; i++) { + result.append("\n"); //$NON-NLS-1$ + result.append(this.memberTypes[i].toString(tab + 1)); + } + } + if (this.fields != null) { + for (int i = 0; i < this.fieldCount; i++) { + result.append("\n"); //$NON-NLS-1$ + result.append(this.fields[i].toString(tab + 1)); + } + } + if (this.methods != null) { + for (int i = 0; i < this.methodCount; i++) { + result.append("\n"); //$NON-NLS-1$ + result.append(this.methods[i].toString(tab + 1)); + } + } + return result.toString(); +} +/* + * Update the bodyStart of the corresponding parse node + */ +public void updateBodyStart(int bodyStart){ + this.foundOpeningBrace = true; + this.typeDeclaration.bodyStart = bodyStart; +} +public Statement updatedStatement(){ + + // ignore closed anonymous type + if (typeDeclaration instanceof AnonymousLocalTypeDeclaration + && !this.preserveContent){ + return null; + } + + TypeDeclaration updatedType = this.updatedTypeDeclaration(); + if (updatedType instanceof AnonymousLocalTypeDeclaration){ + /* in presence of an anonymous type, we want the full allocation expression */ + return ((AnonymousLocalTypeDeclaration)updatedType).allocation; + } + return updatedType; +} +public TypeDeclaration updatedTypeDeclaration(){ + + /* update member types */ + if (memberTypeCount > 0){ + int existingCount = typeDeclaration.memberTypes == null ? 0 : typeDeclaration.memberTypes.length; + MemberTypeDeclaration[] memberTypeDeclarations = new MemberTypeDeclaration[existingCount + memberTypeCount]; + if (existingCount > 0){ + System.arraycopy(typeDeclaration.memberTypes, 0, memberTypeDeclarations, 0, existingCount); + } + // may need to update the declarationSourceEnd of the last type + if (memberTypes[memberTypeCount - 1].typeDeclaration.declarationSourceEnd == 0){ + int bodyEnd = bodyEnd(); + memberTypes[memberTypeCount - 1].typeDeclaration.declarationSourceEnd = bodyEnd; + memberTypes[memberTypeCount - 1].typeDeclaration.bodyEnd = bodyEnd; + } + for (int i = 0; i < memberTypeCount; i++){ + memberTypeDeclarations[existingCount + i] = (MemberTypeDeclaration)memberTypes[i].updatedTypeDeclaration(); + } + typeDeclaration.memberTypes = memberTypeDeclarations; + } + /* update fields */ + if (fieldCount > 0){ + int existingCount = typeDeclaration.fields == null ? 0 : typeDeclaration.fields.length; + FieldDeclaration[] fieldDeclarations = new FieldDeclaration[existingCount + fieldCount]; + if (existingCount > 0){ + System.arraycopy(typeDeclaration.fields, 0, fieldDeclarations, 0, existingCount); + } + // may need to update the declarationSourceEnd of the last field + if (fields[fieldCount - 1].fieldDeclaration.declarationSourceEnd == 0){ + int temp = bodyEnd(); + fields[fieldCount - 1].fieldDeclaration.declarationSourceEnd = temp; + fields[fieldCount - 1].fieldDeclaration.declarationEnd = temp; + } + for (int i = 0; i < fieldCount; i++){ + fieldDeclarations[existingCount + i] = fields[i].updatedFieldDeclaration(); + } + typeDeclaration.fields = fieldDeclarations; + } + /* update methods */ + int existingCount = typeDeclaration.methods == null ? 0 : typeDeclaration.methods.length; + boolean hasConstructor = false, hasRecoveredConstructor = false; + int defaultConstructorIndex = -1; + if (methodCount > 0){ + AbstractMethodDeclaration[] methodDeclarations = new AbstractMethodDeclaration[existingCount + methodCount]; + for (int i = 0; i < existingCount; i++){ + AbstractMethodDeclaration m = typeDeclaration.methods[i]; + if (m.isDefaultConstructor()) defaultConstructorIndex = i; + methodDeclarations[i] = m; + } + // may need to update the declarationSourceEnd of the last method + if (methods[methodCount - 1].methodDeclaration.declarationSourceEnd == 0){ + int bodyEnd = bodyEnd(); + methods[methodCount - 1].methodDeclaration.declarationSourceEnd = bodyEnd; + methods[methodCount - 1].methodDeclaration.bodyEnd = bodyEnd; + } + for (int i = 0; i < methodCount; i++){ + AbstractMethodDeclaration updatedMethod = methods[i].updatedMethodDeclaration(); + if (updatedMethod.isConstructor()) hasRecoveredConstructor = true; + methodDeclarations[existingCount + i] = updatedMethod; + } + typeDeclaration.methods = methodDeclarations; + hasConstructor = typeDeclaration.checkConstructors(this.parser()); + } else { + for (int i = 0; i < existingCount; i++){ + if (typeDeclaration.methods[i].isConstructor()) hasConstructor = true; + } + } + /* add clinit ? */ + if (typeDeclaration.needClassInitMethod()){ + boolean alreadyHasClinit = false; + for (int i = 0; i < existingCount; i++){ + if (typeDeclaration.methods[i].isClinit()){ + alreadyHasClinit = true; + break; + } + } + if (!alreadyHasClinit) typeDeclaration.addClinit(); + } + /* add default constructor ? */ + if (defaultConstructorIndex >= 0 && hasRecoveredConstructor){ + /* should discard previous default construtor */ + AbstractMethodDeclaration[] methodDeclarations = new AbstractMethodDeclaration[typeDeclaration.methods.length - 1]; + if (defaultConstructorIndex != 0){ + System.arraycopy(typeDeclaration.methods, 0, methodDeclarations, 0, defaultConstructorIndex); + } + if (defaultConstructorIndex != typeDeclaration.methods.length-1){ + System.arraycopy( + typeDeclaration.methods, + defaultConstructorIndex+1, + methodDeclarations, + defaultConstructorIndex, + typeDeclaration.methods.length - defaultConstructorIndex - 1); + } + typeDeclaration.methods = methodDeclarations; + } else { + if (!hasConstructor) {// if was already reduced, then constructor + boolean insideFieldInitializer = false; + RecoveredElement parent = this.parent; + while (parent != null){ + if (parent instanceof RecoveredField){ + insideFieldInitializer = true; + break; + } + parent = parent.parent; + } + typeDeclaration.createsInternalConstructor(!parser().diet || insideFieldInitializer, true); + } + } + /* might need to cast itself into a MemberTypeDeclaration or a LocalTypeDeclaration */ + TypeDeclaration newTypeDeclaration = null; + if ((typeDeclaration instanceof TypeDeclaration) && (parent instanceof RecoveredType)){ + newTypeDeclaration = new MemberTypeDeclaration(typeDeclaration.compilationResult); + } else { + if ((typeDeclaration instanceof TypeDeclaration) && (parent instanceof RecoveredMethod)){ + newTypeDeclaration = new LocalTypeDeclaration(typeDeclaration.compilationResult); + } + } + /* copy slots into new type */ + if (newTypeDeclaration != null){ + newTypeDeclaration.modifiers = typeDeclaration.modifiers; + newTypeDeclaration.modifiersSourceStart = typeDeclaration.modifiersSourceStart; + newTypeDeclaration.name = typeDeclaration.name; + newTypeDeclaration.superclass = typeDeclaration.superclass; + newTypeDeclaration.superInterfaces = typeDeclaration.superInterfaces; + newTypeDeclaration.fields = typeDeclaration.fields; + newTypeDeclaration.methods = typeDeclaration.methods; + newTypeDeclaration.memberTypes = typeDeclaration.memberTypes; + newTypeDeclaration.ignoreFurtherInvestigation = typeDeclaration.ignoreFurtherInvestigation; + newTypeDeclaration.maxFieldCount = typeDeclaration.maxFieldCount; + newTypeDeclaration.declarationSourceStart = typeDeclaration.declarationSourceStart; + newTypeDeclaration.declarationSourceEnd = typeDeclaration.declarationSourceEnd; + newTypeDeclaration.bodyEnd = typeDeclaration.bodyEnd; + newTypeDeclaration.bodyStart = typeDeclaration.bodyStart; + typeDeclaration = newTypeDeclaration; + } + return typeDeclaration; +} +/* + * Update the corresponding parse node from parser state which + * is about to disappear because of restarting recovery + */ +public void updateFromParserState(){ + + if(this.bodyStartsAtHeaderEnd()){ + Parser parser = this.parser(); + /* might want to recover implemented interfaces */ + // protection for bugs 15142 + if (parser.listLength > 0 && parser.astLengthPtr > 0){ // awaiting interface type references + int length = parser.astLengthStack[parser.astLengthPtr]; + int astPtr = parser.astPtr - length; + boolean canConsume = astPtr >= 0; + if(canConsume) { + if((!(parser.astStack[astPtr] instanceof TypeDeclaration))) { + canConsume = false; + } + for (int i = 1, max = length + 1; i < max; i++) { + if(!(parser.astStack[astPtr + i ] instanceof TypeReference)) { + canConsume = false; + } + } + } + if(canConsume) { + parser.consumeClassHeaderImplements(); + // will reset typeListLength to zero + // thus this check will only be performed on first errorCheck after class X implements Y,Z, + } + } + } +} +/* + * A closing brace got consumed, might have closed the current element, + * in which case both the currentElement is exited + */ +public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){ + if ((--bracketBalance <= 0) && (parent != null)){ + this.updateSourceEndIfNecessary(braceEnd); + this.bodyEnd = braceStart - 1; + return parent; + } + return this; +} +/* + * An opening brace got consumed, might be the expected opening one of the current element, + * in which case the bodyStart is updated. + */ +public RecoveredElement updateOnOpeningBrace(int braceEnd){ + /* in case the opening brace is not close enough to the signature, ignore it */ + if (bracketBalance == 0){ + /* + if (parser.scanner.searchLineNumber(typeDeclaration.sourceEnd) + != parser.scanner.searchLineNumber(braceEnd)){ + */ + Parser parser = this.parser(); + switch(parser.lastIgnoredToken){ + case -1 : + case TokenNameextends : +// case TokenNameimplements : + if (parser.recoveredStaticInitializerStart == 0) break; + default: + this.foundOpeningBrace = true; + bracketBalance = 1; // pretend the brace was already there + } + } + // might be an initializer + if (this.bracketBalance == 1){ + Block block = new Block(0); + Parser parser = this.parser(); + block.sourceStart = parser.scanner.startPosition; + Initializer init; + if (parser.recoveredStaticInitializerStart == 0){ + init = new Initializer(block, AccDefault); + } else { + init = new Initializer(block, AccStatic); + init.declarationSourceStart = parser.recoveredStaticInitializerStart; + } + return this.add(init, 1); + } + return super.updateOnOpeningBrace(braceEnd); +} +public void updateParseTree(){ + this.updatedTypeDeclaration(); +} +/* + * Update the declarationSourceEnd of the corresponding parse node + */ +public void updateSourceEndIfNecessary(int sourceEnd){ + if (this.typeDeclaration.declarationSourceEnd == 0){ + this.bodyEnd = 0; + this.typeDeclaration.declarationSourceEnd = sourceEnd; + this.typeDeclaration.bodyEnd = sourceEnd; + } +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredUnit.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredUnit.java new file mode 100644 index 0000000..cfcf364 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/RecoveredUnit.java @@ -0,0 +1,205 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.parser; + +/** + * Internal field structure for parsing recovery + */ +import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.AnonymousLocalTypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.ImportReference; +import net.sourceforge.phpdt.internal.compiler.ast.LocalTypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; + +public class RecoveredUnit extends RecoveredElement { + + public CompilationUnitDeclaration unitDeclaration; + + public RecoveredImport[] imports; + public int importCount; + public RecoveredType[] types; + public int typeCount; +public RecoveredUnit(CompilationUnitDeclaration unitDeclaration, int bracketBalance, Parser parser){ + super(null, bracketBalance, parser); + this.unitDeclaration = unitDeclaration; +} +/* + * Record a method declaration: should be attached to last type + */ +public RecoveredElement add(AbstractMethodDeclaration methodDeclaration, int bracketBalance) { + + /* attach it to last type - if any */ + if (typeCount > 0){ + RecoveredType type = this.types[typeCount -1]; + type.bodyEnd = 0; // reset position + type.typeDeclaration.declarationSourceEnd = 0; // reset position + type.typeDeclaration.bodyEnd = 0; + return type.add(methodDeclaration, bracketBalance); + } + return this; // ignore +} +/* + * Record a field declaration: should be attached to last type + */ +public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalance) { + + /* attach it to last type - if any */ + if (typeCount > 0){ + RecoveredType type = this.types[typeCount -1]; + type.bodyEnd = 0; // reset position + type.typeDeclaration.declarationSourceEnd = 0; // reset position + type.typeDeclaration.bodyEnd = 0; + return type.add(fieldDeclaration, bracketBalance); + } + return this; // ignore +} +public RecoveredElement add(ImportReference importReference, int bracketBalance) { + if (imports == null) { + imports = new RecoveredImport[5]; + importCount = 0; + } else { + if (importCount == imports.length) { + System.arraycopy( + imports, + 0, + (imports = new RecoveredImport[2 * importCount]), + 0, + importCount); + } + } + RecoveredImport element = new RecoveredImport(importReference, this, bracketBalance); + imports[importCount++] = element; + + /* if import not finished, then import becomes current */ + if (importReference.declarationSourceEnd == 0) return element; + return this; +} +public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalance) { + + if (typeDeclaration instanceof AnonymousLocalTypeDeclaration){ + if (this.typeCount > 0) { + // add it to the last type + RecoveredType lastType = this.types[this.typeCount-1]; + lastType.bodyEnd = 0; // reopen type + lastType.typeDeclaration.bodyEnd = 0; // reopen type + lastType.typeDeclaration.declarationSourceEnd = 0; // reopen type + lastType.bracketBalance++; // expect one closing brace + return lastType.add(typeDeclaration, bracketBalance); + } + } + if (types == null) { + types = new RecoveredType[5]; + typeCount = 0; + } else { + if (typeCount == types.length) { + System.arraycopy( + types, + 0, + (types = new RecoveredType[2 * typeCount]), + 0, + typeCount); + } + } + RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalance); + types[typeCount++] = element; + + /* if type not finished, then type becomes current */ + if (typeDeclaration.declarationSourceEnd == 0) return element; + return this; +} +/* + * Answer the associated parsed structure + */ +public AstNode parseTree(){ + return unitDeclaration; +} +/* + * Answer the very source end of the corresponding parse node + */ +public int sourceEnd(){ + return this.unitDeclaration.sourceEnd; +} +public String toString(int tab) { + StringBuffer result = new StringBuffer(tabString(tab)); + result.append("Recovered unit: [\n"); //$NON-NLS-1$ + result.append(unitDeclaration.toString(tab + 1)); + result.append(tabString(tab + 1)); + result.append("]"); //$NON-NLS-1$ + if (this.imports != null) { + for (int i = 0; i < this.importCount; i++) { + result.append("\n"); //$NON-NLS-1$ + result.append(this.imports[i].toString(tab + 1)); + } + } + if (this.types != null) { + for (int i = 0; i < this.typeCount; i++) { + result.append("\n"); //$NON-NLS-1$ + result.append(this.types[i].toString(tab + 1)); + } + } + return result.toString(); +} +public CompilationUnitDeclaration updatedCompilationUnitDeclaration(){ + + /* update imports */ + if (importCount > 0){ + ImportReference[] importRefences = new ImportReference[importCount]; + for (int i = 0; i < importCount; i++){ + importRefences[i] = imports[i].updatedImportReference(); + } + unitDeclaration.imports = importRefences; + } + /* update types */ + if (typeCount > 0){ + int existingCount = unitDeclaration.types == null ? 0 : unitDeclaration.types.length; + TypeDeclaration[] typeDeclarations = new TypeDeclaration[existingCount + typeCount]; + if (existingCount > 0){ + System.arraycopy(unitDeclaration.types, 0, typeDeclarations, 0, existingCount); + } + // may need to update the declarationSourceEnd of the last type + if (types[typeCount - 1].typeDeclaration.declarationSourceEnd == 0){ + types[typeCount - 1].typeDeclaration.declarationSourceEnd = unitDeclaration.sourceEnd; + types[typeCount - 1].typeDeclaration.bodyEnd = unitDeclaration.sourceEnd; + } + int actualCount = existingCount; + for (int i = 0; i < typeCount; i++){ + TypeDeclaration typeDecl = types[i].updatedTypeDeclaration(); + // filter out local types (12454) + if (!(typeDecl instanceof LocalTypeDeclaration)){ + typeDeclarations[actualCount++] = typeDecl; + } + } + if (actualCount != typeCount){ + System.arraycopy( + typeDeclarations, + 0, + typeDeclarations = new TypeDeclaration[existingCount+actualCount], + 0, + existingCount+actualCount); + } + unitDeclaration.types = typeDeclarations; + } + return unitDeclaration; +} +public void updateParseTree(){ + this.updatedCompilationUnitDeclaration(); +} +/* + * Update the sourceEnd of the corresponding parse node + */ +public void updateSourceEndIfNecessary(int sourceEnd){ + if (this.unitDeclaration.sourceEnd == 0) + this.unitDeclaration.sourceEnd = sourceEnd; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/Scanner.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/Scanner.java new file mode 100644 index 0000000..7fc7e5c --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/Scanner.java @@ -0,0 +1,2830 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.parser; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import net.sourceforge.phpdt.core.compiler.IScanner; +import net.sourceforge.phpdt.core.compiler.ITerminalSymbols; +import net.sourceforge.phpdt.core.compiler.InvalidInputException; +import net.sourceforge.phpdt.internal.compiler.ast.StringLiteral; + +public class Scanner implements IScanner, ITerminalSymbols { + + /* APIs ares + - getNextToken() which return the current type of the token + (this value is not memorized by the scanner) + - getCurrentTokenSource() which provides with the token "REAL" source + (aka all unicode have been transformed into a correct char) + - sourceStart gives the position into the stream + - currentPosition-1 gives the sourceEnd position into the stream + */ + + // 1.4 feature + private boolean assertMode; + public boolean useAssertAsAnIndentifier = false; + //flag indicating if processed source contains occurrences of keyword assert + public boolean containsAssertKeyword = false; + + public boolean recordLineSeparator; + public char currentCharacter; + public int startPosition; + public int currentPosition; + public int initialPosition, eofPosition; + // after this position eof are generated instead of real token from the source + + public boolean tokenizeComments; + public boolean tokenizeWhiteSpace; + + //source should be viewed as a window (aka a part) + //of a entire very large stream + public char source[]; + + //unicode support + public char[] withoutUnicodeBuffer; + public int withoutUnicodePtr; //when == 0 ==> no unicode in the current token + public boolean unicodeAsBackSlash = false; + + public boolean scanningFloatLiteral = false; + + //support for /** comments + //public char[][] comments = new char[10][]; + public int[] commentStops = new int[10]; + public int[] commentStarts = new int[10]; + public int commentPtr = -1; // no comment test with commentPtr value -1 + + //diet parsing support - jump over some method body when requested + public boolean diet = false; + + //support for the poor-line-debuggers .... + //remember the position of the cr/lf + public int[] lineEnds = new int[250]; + public int linePtr = -1; + public boolean wasAcr = false; + + public static final String END_OF_SOURCE = "End_Of_Source"; //$NON-NLS-1$ + + public static final String INVALID_HEXA = "Invalid_Hexa_Literal"; //$NON-NLS-1$ + public static final String INVALID_OCTAL = "Invalid_Octal_Literal"; //$NON-NLS-1$ + public static final String INVALID_CHARACTER_CONSTANT = "Invalid_Character_Constant"; //$NON-NLS-1$ + public static final String INVALID_ESCAPE = "Invalid_Escape"; //$NON-NLS-1$ + public static final String INVALID_INPUT = "Invalid_Input"; //$NON-NLS-1$ + public static final String INVALID_UNICODE_ESCAPE = "Invalid_Unicode_Escape"; //$NON-NLS-1$ + public static final String INVALID_FLOAT = "Invalid_Float_Literal"; //$NON-NLS-1$ + + public static final String NULL_SOURCE_STRING = "Null_Source_String"; //$NON-NLS-1$ + public static final String UNTERMINATED_STRING = "Unterminated_String"; //$NON-NLS-1$ + public static final String UNTERMINATED_COMMENT = "Unterminated_Comment"; //$NON-NLS-1$ + public static final String INVALID_CHAR_IN_STRING = "Invalid_Char_In_String"; //$NON-NLS-1$ + + //----------------optimized identifier managment------------------ + static final char[] charArray_a = new char[] { 'a' }, + charArray_b = new char[] { 'b' }, + charArray_c = new char[] { 'c' }, + charArray_d = new char[] { 'd' }, + charArray_e = new char[] { 'e' }, + charArray_f = new char[] { 'f' }, + charArray_g = new char[] { 'g' }, + charArray_h = new char[] { 'h' }, + charArray_i = new char[] { 'i' }, + charArray_j = new char[] { 'j' }, + charArray_k = new char[] { 'k' }, + charArray_l = new char[] { 'l' }, + charArray_m = new char[] { 'm' }, + charArray_n = new char[] { 'n' }, + charArray_o = new char[] { 'o' }, + charArray_p = new char[] { 'p' }, + charArray_q = new char[] { 'q' }, + charArray_r = new char[] { 'r' }, + charArray_s = new char[] { 's' }, + charArray_t = new char[] { 't' }, + charArray_u = new char[] { 'u' }, + charArray_v = new char[] { 'v' }, + charArray_w = new char[] { 'w' }, + charArray_x = new char[] { 'x' }, + charArray_y = new char[] { 'y' }, + charArray_z = new char[] { 'z' }; + + static final char[] initCharArray = new char[] { '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000' }; + static final int TableSize = 30, InternalTableSize = 6; //30*6 = 180 entries + public static final int OptimizedLength = 6; + public /*static*/ + final char[][][][] charArray_length = new char[OptimizedLength][TableSize][InternalTableSize][]; + // support for detecting non-externalized string literals + int currentLineNr = -1; + int previousLineNr = -1; + NLSLine currentLine = null; + List lines = new ArrayList(); + public static final String TAG_PREFIX = "//$NON-NLS-"; //$NON-NLS-1$ + public static final int TAG_PREFIX_LENGTH = TAG_PREFIX.length(); + public static final String TAG_POSTFIX = "$"; //$NON-NLS-1$ + public static final int TAG_POSTFIX_LENGTH = TAG_POSTFIX.length(); + public StringLiteral[] nonNLSStrings = null; + public boolean checkNonExternalizedStringLiterals = true; + public boolean wasNonExternalizedStringLiteral = false; + + /*static*/ { + for (int i = 0; i < 6; i++) { + for (int j = 0; j < TableSize; j++) { + for (int k = 0; k < InternalTableSize; k++) { + charArray_length[i][j][k] = initCharArray; + } + } + } + } + static int newEntry2 = 0, newEntry3 = 0, newEntry4 = 0, newEntry5 = 0, newEntry6 = 0; + + public static final int RoundBracket = 0; + public static final int SquareBracket = 1; + public static final int CurlyBracket = 2; + public static final int BracketKinds = 3; + public Scanner() { + this(false, false); + } + public Scanner(boolean tokenizeComments, boolean tokenizeWhiteSpace) { + this(tokenizeComments, tokenizeWhiteSpace, false); + } + public final boolean atEnd() { + // This code is not relevant if source is + // Only a part of the real stream input + + return source.length == currentPosition; + } + public char[] getCurrentIdentifierSource() { + //return the token REAL source (aka unicodes are precomputed) + + char[] result; + if (withoutUnicodePtr != 0) + //0 is used as a fast test flag so the real first char is in position 1 + System.arraycopy(withoutUnicodeBuffer, 1, result = new char[withoutUnicodePtr], 0, withoutUnicodePtr); + else { + int length = currentPosition - startPosition; + switch (length) { // see OptimizedLength + case 1 : + return optimizedCurrentTokenSource1(); + case 2 : + return optimizedCurrentTokenSource2(); + case 3 : + return optimizedCurrentTokenSource3(); + case 4 : + return optimizedCurrentTokenSource4(); + case 5 : + return optimizedCurrentTokenSource5(); + case 6 : + return optimizedCurrentTokenSource6(); + } + //no optimization + System.arraycopy(source, startPosition, result = new char[length], 0, length); + } + return result; + } + public int getCurrentTokenEndPosition() { + return this.currentPosition - 1; + } + public final char[] getCurrentTokenSource() { + // Return the token REAL source (aka unicodes are precomputed) + + char[] result; + if (withoutUnicodePtr != 0) + // 0 is used as a fast test flag so the real first char is in position 1 + System.arraycopy(withoutUnicodeBuffer, 1, result = new char[withoutUnicodePtr], 0, withoutUnicodePtr); + else { + int length; + System.arraycopy(source, startPosition, result = new char[length = currentPosition - startPosition], 0, length); + } + return result; + } + public final char[] getCurrentTokenSourceString() { + //return the token REAL source (aka unicodes are precomputed). + //REMOVE the two " that are at the beginning and the end. + + char[] result; + if (withoutUnicodePtr != 0) + //0 is used as a fast test flag so the real first char is in position 1 + System.arraycopy(withoutUnicodeBuffer, 2, + //2 is 1 (real start) + 1 (to jump over the ") + result = new char[withoutUnicodePtr - 2], 0, withoutUnicodePtr - 2); + else { + int length; + System.arraycopy(source, startPosition + 1, result = new char[length = currentPosition - startPosition - 2], 0, length); + } + return result; + } + public int getCurrentTokenStartPosition() { + return this.startPosition; + } + /* + * Search the source position corresponding to the end of a given line number + * + * Line numbers are 1-based, and relative to the scanner initialPosition. + * Character positions are 0-based. + * + * In case the given line number is inconsistent, answers -1. + */ + public final int getLineEnd(int lineNumber) { + + if (lineEnds == null) + return -1; + if (lineNumber >= lineEnds.length) + return -1; + if (lineNumber <= 0) + return -1; + + if (lineNumber == lineEnds.length - 1) + return eofPosition; + return lineEnds[lineNumber - 1]; // next line start one character behind the lineEnd of the previous line + } + /** + * Search the source position corresponding to the beginning of a given line number + * + * Line numbers are 1-based, and relative to the scanner initialPosition. + * Character positions are 0-based. + * + * e.g. getLineStart(1) --> 0 i.e. first line starts at character 0. + * + * In case the given line number is inconsistent, answers -1. + */ + public final int getLineStart(int lineNumber) { + + if (lineEnds == null) + return -1; + if (lineNumber >= lineEnds.length) + return -1; + if (lineNumber <= 0) + return -1; + + if (lineNumber == 1) + return initialPosition; + return lineEnds[lineNumber - 2] + 1; // next line start one character behind the lineEnd of the previous line + } + public final boolean getNextChar(char testedChar) { + //BOOLEAN + //handle the case of unicode. + //when a unicode appears then we must use a buffer that holds char internal values + //At the end of this method currentCharacter holds the new visited char + //and currentPosition points right next after it + //Both previous lines are true if the currentCharacter is == to the testedChar + //On false, no side effect has occured. + + //ALL getNextChar.... ARE OPTIMIZED COPIES + + int temp = currentPosition; + try { + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1, c2, c3, c4; + int unicodeSize = 6; + currentPosition++; + while (source[currentPosition] == 'u') { + currentPosition++; + unicodeSize++; + } + + if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15 || c1 < 0) + || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0) + || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0) + || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) { + currentPosition = temp; + return false; + } + + currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + if (currentCharacter != testedChar) { + currentPosition = temp; + return false; + } + unicodeAsBackSlash = currentCharacter == '\\'; + + //need the unicode buffer + if (withoutUnicodePtr == 0) { + //buffer all the entries that have been left aside.... + withoutUnicodePtr = currentPosition - unicodeSize - startPosition; + System.arraycopy(source, startPosition, withoutUnicodeBuffer, 1, withoutUnicodePtr); + } + //fill the buffer with the char + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + return true; + + } //-------------end unicode traitement-------------- + else { + if (currentCharacter != testedChar) { + currentPosition = temp; + return false; + } + unicodeAsBackSlash = false; + if (withoutUnicodePtr != 0) + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + return true; + } + } catch (IndexOutOfBoundsException e) { + unicodeAsBackSlash = false; + currentPosition = temp; + return false; + } + } + public final int getNextChar(char testedChar1, char testedChar2) { + //INT 0 : testChar1 \\\\///\\\\ 1 : testedChar2 \\\\///\\\\ -1 : others + //test can be done with (x==0) for the first and (x>0) for the second + //handle the case of unicode. + //when a unicode appears then we must use a buffer that holds char internal values + //At the end of this method currentCharacter holds the new visited char + //and currentPosition points right next after it + //Both previous lines are true if the currentCharacter is == to the testedChar1/2 + //On false, no side effect has occured. + + //ALL getNextChar.... ARE OPTIMIZED COPIES + + int temp = currentPosition; + try { + int result; + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1, c2, c3, c4; + int unicodeSize = 6; + currentPosition++; + while (source[currentPosition] == 'u') { + currentPosition++; + unicodeSize++; + } + + if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15 || c1 < 0) + || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0) + || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0) + || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) { + currentPosition = temp; + return 2; + } + + currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + if (currentCharacter == testedChar1) + result = 0; + else if (currentCharacter == testedChar2) + result = 1; + else { + currentPosition = temp; + return -1; + } + + //need the unicode buffer + if (withoutUnicodePtr == 0) { + //buffer all the entries that have been left aside.... + withoutUnicodePtr = currentPosition - unicodeSize - startPosition; + System.arraycopy(source, startPosition, withoutUnicodeBuffer, 1, withoutUnicodePtr); + } + //fill the buffer with the char + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + return result; + } //-------------end unicode traitement-------------- + else { + if (currentCharacter == testedChar1) + result = 0; + else if (currentCharacter == testedChar2) + result = 1; + else { + currentPosition = temp; + return -1; + } + + if (withoutUnicodePtr != 0) + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + return result; + } + } catch (IndexOutOfBoundsException e) { + currentPosition = temp; + return -1; + } + } + public final boolean getNextCharAsDigit() { + //BOOLEAN + //handle the case of unicode. + //when a unicode appears then we must use a buffer that holds char internal values + //At the end of this method currentCharacter holds the new visited char + //and currentPosition points right next after it + //Both previous lines are true if the currentCharacter is a digit + //On false, no side effect has occured. + + //ALL getNextChar.... ARE OPTIMIZED COPIES + + int temp = currentPosition; + try { + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1, c2, c3, c4; + int unicodeSize = 6; + currentPosition++; + while (source[currentPosition] == 'u') { + currentPosition++; + unicodeSize++; + } + + if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15 || c1 < 0) + || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0) + || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0) + || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) { + currentPosition = temp; + return false; + } + + currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + if (!Character.isDigit(currentCharacter)) { + currentPosition = temp; + return false; + } + + //need the unicode buffer + if (withoutUnicodePtr == 0) { + //buffer all the entries that have been left aside.... + withoutUnicodePtr = currentPosition - unicodeSize - startPosition; + System.arraycopy(source, startPosition, withoutUnicodeBuffer, 1, withoutUnicodePtr); + } + //fill the buffer with the char + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + return true; + } //-------------end unicode traitement-------------- + else { + if (!Character.isDigit(currentCharacter)) { + currentPosition = temp; + return false; + } + if (withoutUnicodePtr != 0) + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + return true; + } + } catch (IndexOutOfBoundsException e) { + currentPosition = temp; + return false; + } + } + public final boolean getNextCharAsDigit(int radix) { + //BOOLEAN + //handle the case of unicode. + //when a unicode appears then we must use a buffer that holds char internal values + //At the end of this method currentCharacter holds the new visited char + //and currentPosition points right next after it + //Both previous lines are true if the currentCharacter is a digit base on radix + //On false, no side effect has occured. + + //ALL getNextChar.... ARE OPTIMIZED COPIES + + int temp = currentPosition; + try { + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1, c2, c3, c4; + int unicodeSize = 6; + currentPosition++; + while (source[currentPosition] == 'u') { + currentPosition++; + unicodeSize++; + } + + if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15 || c1 < 0) + || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0) + || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0) + || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) { + currentPosition = temp; + return false; + } + + currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + if (Character.digit(currentCharacter, radix) == -1) { + currentPosition = temp; + return false; + } + + //need the unicode buffer + if (withoutUnicodePtr == 0) { + //buffer all the entries that have been left aside.... + withoutUnicodePtr = currentPosition - unicodeSize - startPosition; + System.arraycopy(source, startPosition, withoutUnicodeBuffer, 1, withoutUnicodePtr); + } + //fill the buffer with the char + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + return true; + } //-------------end unicode traitement-------------- + else { + if (Character.digit(currentCharacter, radix) == -1) { + currentPosition = temp; + return false; + } + if (withoutUnicodePtr != 0) + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + return true; + } + } catch (IndexOutOfBoundsException e) { + currentPosition = temp; + return false; + } + } + public boolean getNextCharAsJavaIdentifierPart() { + //BOOLEAN + //handle the case of unicode. + //when a unicode appears then we must use a buffer that holds char internal values + //At the end of this method currentCharacter holds the new visited char + //and currentPosition points right next after it + //Both previous lines are true if the currentCharacter is a JavaIdentifierPart + //On false, no side effect has occured. + + //ALL getNextChar.... ARE OPTIMIZED COPIES + + int temp = currentPosition; + try { + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1, c2, c3, c4; + int unicodeSize = 6; + currentPosition++; + while (source[currentPosition] == 'u') { + currentPosition++; + unicodeSize++; + } + + if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15 || c1 < 0) + || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0) + || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0) + || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) { + currentPosition = temp; + return false; + } + + currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + if (!Character.isJavaIdentifierPart(currentCharacter)) { + currentPosition = temp; + return false; + } + + //need the unicode buffer + if (withoutUnicodePtr == 0) { + //buffer all the entries that have been left aside.... + withoutUnicodePtr = currentPosition - unicodeSize - startPosition; + System.arraycopy(source, startPosition, withoutUnicodeBuffer, 1, withoutUnicodePtr); + } + //fill the buffer with the char + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + return true; + } //-------------end unicode traitement-------------- + else { + if (!Character.isJavaIdentifierPart(currentCharacter)) { + currentPosition = temp; + return false; + } + + if (withoutUnicodePtr != 0) + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + return true; + } + } catch (IndexOutOfBoundsException e) { + currentPosition = temp; + return false; + } + } + public int getNextToken() throws InvalidInputException { + + this.wasAcr = false; + if (diet) { + jumpOverMethodBody(); + diet = false; + return currentPosition > source.length ? TokenNameEOF : TokenNameRBRACE; + } + try { + while (true) { //loop for jumping over comments + withoutUnicodePtr = 0; + //start with a new token (even comment written with unicode ) + + // ---------Consume white space and handles startPosition--------- + int whiteStart = currentPosition; + boolean isWhiteSpace; + do { + startPosition = currentPosition; + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + isWhiteSpace = jumpOverUnicodeWhiteSpace(); + } else { + if ((currentCharacter == '\r') || (currentCharacter == '\n')) { + checkNonExternalizeString(); + if (recordLineSeparator) { + pushLineSeparator(); + } else { + currentLine = null; + } + } + isWhiteSpace = (currentCharacter == ' ') || Character.isWhitespace(currentCharacter); + } + } while (isWhiteSpace); + if (tokenizeWhiteSpace && (whiteStart != currentPosition - 1)) { + // reposition scanner in case we are interested by spaces as tokens + currentPosition--; + startPosition = whiteStart; + return TokenNameWHITESPACE; + } + //little trick to get out in the middle of a source compuation + if (currentPosition > eofPosition) + return TokenNameEOF; + + // ---------Identify the next token------------- + + switch (currentCharacter) { + case '(' : + return TokenNameLPAREN; + case ')' : + return TokenNameRPAREN; + case '{' : + return TokenNameLBRACE; + case '}' : + return TokenNameRBRACE; + case '[' : + return TokenNameLBRACKET; + case ']' : + return TokenNameRBRACKET; + case ';' : + return TokenNameSEMICOLON; + case ',' : + return TokenNameCOMMA; + case '.' : + if (getNextCharAsDigit()) + return scanNumber(true); + return TokenNameDOT; + case '+' : + { + int test; + if ((test = getNextChar('+', '=')) == 0) + return TokenNamePLUS_PLUS; + if (test > 0) + return TokenNamePLUS_EQUAL; + return TokenNamePLUS; + } + case '-' : + { + int test; + if ((test = getNextChar('-', '=')) == 0) + return TokenNameMINUS_MINUS; + if (test > 0) + return TokenNameMINUS_EQUAL; + return TokenNameMINUS; + } + case '~' : + return TokenNameTWIDDLE; + case '!' : + if (getNextChar('=')) + return TokenNameNOT_EQUAL; + return TokenNameNOT; + case '*' : + if (getNextChar('=')) + return TokenNameMULTIPLY_EQUAL; + return TokenNameMULTIPLY; + case '%' : + if (getNextChar('=')) + return TokenNameREMAINDER_EQUAL; + return TokenNameREMAINDER; + case '<' : + { + int test; + if ((test = getNextChar('=', '<')) == 0) + return TokenNameLESS_EQUAL; + if (test > 0) { + if (getNextChar('=')) + return TokenNameLEFT_SHIFT_EQUAL; + return TokenNameLEFT_SHIFT; + } + return TokenNameLESS; + } + case '>' : + { + int test; + if ((test = getNextChar('=', '>')) == 0) + return TokenNameGREATER_EQUAL; + if (test > 0) { + if ((test = getNextChar('=', '>')) == 0) + return TokenNameRIGHT_SHIFT_EQUAL; + if (test > 0) { + if (getNextChar('=')) + return TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL; + return TokenNameUNSIGNED_RIGHT_SHIFT; + } + return TokenNameRIGHT_SHIFT; + } + return TokenNameGREATER; + } + case '=' : + if (getNextChar('=')) + return TokenNameEQUAL_EQUAL; + return TokenNameEQUAL; + case '&' : + { + int test; + if ((test = getNextChar('&', '=')) == 0) + return TokenNameAND_AND; + if (test > 0) + return TokenNameAND_EQUAL; + return TokenNameAND; + } + case '|' : + { + int test; + if ((test = getNextChar('|', '=')) == 0) + return TokenNameOR_OR; + if (test > 0) + return TokenNameOR_EQUAL; + return TokenNameOR; + } + case '^' : + if (getNextChar('=')) + return TokenNameXOR_EQUAL; + return TokenNameXOR; + case '?' : + return TokenNameQUESTION; + case ':' : + return TokenNameCOLON; + case '\'' : + { + int test; + if ((test = getNextChar('\n', '\r')) == 0) { + throw new InvalidInputException(INVALID_CHARACTER_CONSTANT); + } + if (test > 0) { + // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed + for (int lookAhead = 0; lookAhead < 3; lookAhead++) { + if (currentPosition + lookAhead == source.length) + break; + if (source[currentPosition + lookAhead] == '\n') + break; + if (source[currentPosition + lookAhead] == '\'') { + currentPosition += lookAhead + 1; + break; + } + } + throw new InvalidInputException(INVALID_CHARACTER_CONSTANT); + } + } + if (getNextChar('\'')) { + // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed + for (int lookAhead = 0; lookAhead < 3; lookAhead++) { + if (currentPosition + lookAhead == source.length) + break; + if (source[currentPosition + lookAhead] == '\n') + break; + if (source[currentPosition + lookAhead] == '\'') { + currentPosition += lookAhead + 1; + break; + } + } + throw new InvalidInputException(INVALID_CHARACTER_CONSTANT); + } + if (getNextChar('\\')) + scanEscapeCharacter(); + else { // consume next character + unicodeAsBackSlash = false; + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (withoutUnicodePtr != 0) { + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + } + } + if (getNextChar('\'')) + return TokenNameCharacterLiteral; + // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed + for (int lookAhead = 0; lookAhead < 20; lookAhead++) { + if (currentPosition + lookAhead == source.length) + break; + if (source[currentPosition + lookAhead] == '\n') + break; + if (source[currentPosition + lookAhead] == '\'') { + currentPosition += lookAhead + 1; + break; + } + } + throw new InvalidInputException(INVALID_CHARACTER_CONSTANT); + case '"' : + try { + // consume next character + unicodeAsBackSlash = false; + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (withoutUnicodePtr != 0) { + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + } + + while (currentCharacter != '"') { + /**** \r and \n are not valid in string literals ****/ + if ((currentCharacter == '\n') || (currentCharacter == '\r')) { + // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed + for (int lookAhead = 0; lookAhead < 50; lookAhead++) { + if (currentPosition + lookAhead == source.length) + break; + if (source[currentPosition + lookAhead] == '\n') + break; + if (source[currentPosition + lookAhead] == '\"') { + currentPosition += lookAhead + 1; + break; + } + } + throw new InvalidInputException(INVALID_CHAR_IN_STRING); + } + if (currentCharacter == '\\') { + int escapeSize = currentPosition; + boolean backSlashAsUnicodeInString = unicodeAsBackSlash; + //scanEscapeCharacter make a side effect on this value and we need the previous value few lines down this one + scanEscapeCharacter(); + escapeSize = currentPosition - escapeSize; + if (withoutUnicodePtr == 0) { + //buffer all the entries that have been left aside.... + withoutUnicodePtr = currentPosition - escapeSize - 1 - startPosition; + System.arraycopy(source, startPosition, withoutUnicodeBuffer, 1, withoutUnicodePtr); + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } else { //overwrite the / in the buffer + withoutUnicodeBuffer[withoutUnicodePtr] = currentCharacter; + if (backSlashAsUnicodeInString) { //there are TWO \ in the stream where only one is correct + withoutUnicodePtr--; + } + } + } + // consume next character + unicodeAsBackSlash = false; + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (withoutUnicodePtr != 0) { + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + } + + } + } catch (IndexOutOfBoundsException e) { + throw new InvalidInputException(UNTERMINATED_STRING); + } catch (InvalidInputException e) { + if (e.getMessage().equals(INVALID_ESCAPE)) { + // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed + for (int lookAhead = 0; lookAhead < 50; lookAhead++) { + if (currentPosition + lookAhead == source.length) + break; + if (source[currentPosition + lookAhead] == '\n') + break; + if (source[currentPosition + lookAhead] == '\"') { + currentPosition += lookAhead + 1; + break; + } + } + + } + throw e; // rethrow + } + if (checkNonExternalizedStringLiterals) { // check for presence of NLS tags //$NON-NLS-?$ where ? is an int. + if (currentLine == null) { + currentLine = new NLSLine(); + lines.add(currentLine); + } + currentLine.add(new StringLiteral(getCurrentTokenSourceString(), startPosition, currentPosition - 1)); + } + return TokenNameStringLiteral; + case '/' : + { + int test; + if ((test = getNextChar('/', '*')) == 0) { //line comment + int endPositionForLineComment = 0; + try { //get the next char + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + currentPosition++; + while (source[currentPosition] == 'u') { + currentPosition++; + } + if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(source[currentPosition++])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(source[currentPosition++])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(source[currentPosition++])) > 15 + || c4 < 0) { + throw new InvalidInputException(INVALID_UNICODE_ESCAPE); + } else { + currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + } + + //handle the \\u case manually into comment + if (currentCharacter == '\\') { + if (source[currentPosition] == '\\') + currentPosition++; + } //jump over the \\ + boolean isUnicode = false; + while (currentCharacter != '\r' && currentCharacter != '\n') { + //get the next char + isUnicode = false; + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + isUnicode = true; + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + currentPosition++; + while (source[currentPosition] == 'u') { + currentPosition++; + } + if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(source[currentPosition++])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(source[currentPosition++])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(source[currentPosition++])) > 15 + || c4 < 0) { + throw new InvalidInputException(INVALID_UNICODE_ESCAPE); + } else { + currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + } + //handle the \\u case manually into comment + if (currentCharacter == '\\') { + if (source[currentPosition] == '\\') + currentPosition++; + } //jump over the \\ + } + if (isUnicode) { + endPositionForLineComment = currentPosition - 6; + } else { + endPositionForLineComment = currentPosition - 1; + } + recordComment(false); + if ((currentCharacter == '\r') || (currentCharacter == '\n')) { + checkNonExternalizeString(); + if (recordLineSeparator) { + if (isUnicode) { + pushUnicodeLineSeparator(); + } else { + pushLineSeparator(); + } + } else { + currentLine = null; + } + } + if (tokenizeComments) { + if (!isUnicode) { + currentPosition = endPositionForLineComment; // reset one character behind + } + return TokenNameCOMMENT_LINE; + } + } catch (IndexOutOfBoundsException e) { //an eof will them be generated + if (tokenizeComments) { + currentPosition--; // reset one character behind + return TokenNameCOMMENT_LINE; + } + } + break; + } + if (test > 0) { //traditional and annotation comment + boolean isJavadoc = false, star = false; + // consume next character + unicodeAsBackSlash = false; + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (withoutUnicodePtr != 0) { + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + } + + if (currentCharacter == '*') { + isJavadoc = true; + star = true; + } + if ((currentCharacter == '\r') || (currentCharacter == '\n')) { + checkNonExternalizeString(); + if (recordLineSeparator) { + pushLineSeparator(); + } else { + currentLine = null; + } + } + try { //get the next char + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + //-------------unicode traitement ------------ + getNextUnicodeChar(); + } + //handle the \\u case manually into comment + if (currentCharacter == '\\') { + if (source[currentPosition] == '\\') + currentPosition++; //jump over the \\ + } + // empty comment is not a javadoc /**/ + if (currentCharacter == '/') { + isJavadoc = false; + } + //loop until end of comment */ + while ((currentCharacter != '/') || (!star)) { + if ((currentCharacter == '\r') || (currentCharacter == '\n')) { + checkNonExternalizeString(); + if (recordLineSeparator) { + pushLineSeparator(); + } else { + currentLine = null; + } + } + star = currentCharacter == '*'; + //get next char + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + //-------------unicode traitement ------------ + getNextUnicodeChar(); + } + //handle the \\u case manually into comment + if (currentCharacter == '\\') { + if (source[currentPosition] == '\\') + currentPosition++; + } //jump over the \\ + } + recordComment(isJavadoc); + if (tokenizeComments) { + if (isJavadoc) + return TokenNameCOMMENT_JAVADOC; + return TokenNameCOMMENT_BLOCK; + } + } catch (IndexOutOfBoundsException e) { + throw new InvalidInputException(UNTERMINATED_COMMENT); + } + break; + } + if (getNextChar('=')) + return TokenNameDIVIDE_EQUAL; + return TokenNameDIVIDE; + } + case '\u001a' : + if (atEnd()) + return TokenNameEOF; + //the atEnd may not be if source is only some part of a real (external) stream + throw new InvalidInputException("Ctrl-Z"); //$NON-NLS-1$ + + default : + if (Character.isJavaIdentifierStart(currentCharacter)) + return scanIdentifierOrKeyword(); + if (Character.isDigit(currentCharacter)) + return scanNumber(false); + return TokenNameERROR; + } + } + } //-----------------end switch while try-------------------- + catch (IndexOutOfBoundsException e) { + } + return TokenNameEOF; + } + public final void getNextUnicodeChar() throws IndexOutOfBoundsException, InvalidInputException { + //VOID + //handle the case of unicode. + //when a unicode appears then we must use a buffer that holds char internal values + //At the end of this method currentCharacter holds the new visited char + //and currentPosition points right next after it + + //ALL getNextChar.... ARE OPTIMIZED COPIES + + int c1 = 0, c2 = 0, c3 = 0, c4 = 0, unicodeSize = 6; + currentPosition++; + while (source[currentPosition] == 'u') { + currentPosition++; + unicodeSize++; + } + + if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(source[currentPosition++])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(source[currentPosition++])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(source[currentPosition++])) > 15 + || c4 < 0) { + throw new InvalidInputException(INVALID_UNICODE_ESCAPE); + } else { + currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + //need the unicode buffer + if (withoutUnicodePtr == 0) { + //buffer all the entries that have been left aside.... + withoutUnicodePtr = currentPosition - unicodeSize - startPosition; + System.arraycopy(source, startPosition, withoutUnicodeBuffer, 1, withoutUnicodePtr); + } + //fill the buffer with the char + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + unicodeAsBackSlash = currentCharacter == '\\'; + } + /* Tokenize a method body, assuming that curly brackets are properly balanced. + */ + public final void jumpOverMethodBody() { + + this.wasAcr = false; + int found = 1; + try { + while (true) { //loop for jumping over comments + // ---------Consume white space and handles startPosition--------- + boolean isWhiteSpace; + do { + startPosition = currentPosition; + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + isWhiteSpace = jumpOverUnicodeWhiteSpace(); + } else { + if (recordLineSeparator && ((currentCharacter == '\r') || (currentCharacter == '\n'))) + pushLineSeparator(); + isWhiteSpace = Character.isWhitespace(currentCharacter); + } + } while (isWhiteSpace); + + // -------consume token until } is found--------- + switch (currentCharacter) { + case '{' : + found++; + break; + case '}' : + found--; + if (found == 0) + return; + break; + case '\'' : + { + boolean test; + test = getNextChar('\\'); + if (test) { + try { + scanEscapeCharacter(); + } catch (InvalidInputException ex) { + }; + } else { + try { // consume next character + unicodeAsBackSlash = false; + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (withoutUnicodePtr != 0) { + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + } + } catch (InvalidInputException ex) { + }; + } + getNextChar('\''); + break; + } + case '"' : + try { + try { // consume next character + unicodeAsBackSlash = false; + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (withoutUnicodePtr != 0) { + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + } + } catch (InvalidInputException ex) { + }; + while (currentCharacter != '"') { + if (currentCharacter == '\r') { + if (source[currentPosition] == '\n') + currentPosition++; + break; // the string cannot go further that the line + } + if (currentCharacter == '\n') { + break; // the string cannot go further that the line + } + if (currentCharacter == '\\') { + try { + scanEscapeCharacter(); + } catch (InvalidInputException ex) { + }; + } + try { // consume next character + unicodeAsBackSlash = false; + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (withoutUnicodePtr != 0) { + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + } + } catch (InvalidInputException ex) { + }; + } + } catch (IndexOutOfBoundsException e) { + return; + } + break; + case '/' : + { + int test; + if ((test = getNextChar('/', '*')) == 0) { //line comment + try { + //get the next char + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + currentPosition++; + while (source[currentPosition] == 'u') { + currentPosition++; + } + if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(source[currentPosition++])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(source[currentPosition++])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(source[currentPosition++])) > 15 + || c4 < 0) { //error don't care of the value + currentCharacter = 'A'; + } //something different from \n and \r + else { + currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + } + + while (currentCharacter != '\r' && currentCharacter != '\n') { + //get the next char + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + currentPosition++; + while (source[currentPosition] == 'u') { + currentPosition++; + } + if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(source[currentPosition++])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(source[currentPosition++])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(source[currentPosition++])) > 15 + || c4 < 0) { //error don't care of the value + currentCharacter = 'A'; + } //something different from \n and \r + else { + currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + } + } + if (recordLineSeparator && ((currentCharacter == '\r') || (currentCharacter == '\n'))) + pushLineSeparator(); + } catch (IndexOutOfBoundsException e) { + } //an eof will them be generated + break; + } + if (test > 0) { //traditional and annotation comment + boolean star = false; + try { // consume next character + unicodeAsBackSlash = false; + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (withoutUnicodePtr != 0) { + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + }; + } catch (InvalidInputException ex) { + }; + if (currentCharacter == '*') { + star = true; + } + if (recordLineSeparator && ((currentCharacter == '\r') || (currentCharacter == '\n'))) + pushLineSeparator(); + try { //get the next char + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + currentPosition++; + while (source[currentPosition] == 'u') { + currentPosition++; + } + if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(source[currentPosition++])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(source[currentPosition++])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(source[currentPosition++])) > 15 + || c4 < 0) { //error don't care of the value + currentCharacter = 'A'; + } //something different from * and / + else { + currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + } + //loop until end of comment */ + while ((currentCharacter != '/') || (!star)) { + if (recordLineSeparator && ((currentCharacter == '\r') || (currentCharacter == '\n'))) + pushLineSeparator(); + star = currentCharacter == '*'; + //get next char + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + currentPosition++; + while (source[currentPosition] == 'u') { + currentPosition++; + } + if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(source[currentPosition++])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(source[currentPosition++])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(source[currentPosition++])) > 15 + || c4 < 0) { //error don't care of the value + currentCharacter = 'A'; + } //something different from * and / + else { + currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + } + } + } catch (IndexOutOfBoundsException e) { + return; + } + break; + } + break; + } + + default : + if (Character.isJavaIdentifierStart(currentCharacter)) { + try { + scanIdentifierOrKeyword(); + } catch (InvalidInputException ex) { + }; + break; + } + if (Character.isDigit(currentCharacter)) { + try { + scanNumber(false); + } catch (InvalidInputException ex) { + }; + break; + } + } + } + //-----------------end switch while try-------------------- + } catch (IndexOutOfBoundsException e) { + } catch (InvalidInputException e) { + } + return; + } + public final boolean jumpOverUnicodeWhiteSpace() throws InvalidInputException { + //BOOLEAN + //handle the case of unicode. Jump over the next whiteSpace + //making startPosition pointing on the next available char + //On false, the currentCharacter is filled up with a potential + //correct char + + try { + this.wasAcr = false; + int c1, c2, c3, c4; + int unicodeSize = 6; + currentPosition++; + while (source[currentPosition] == 'u') { + currentPosition++; + unicodeSize++; + } + + if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15 || c1 < 0) + || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0) + || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0) + || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) { + throw new InvalidInputException(INVALID_UNICODE_ESCAPE); + } + + currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + if (recordLineSeparator && ((currentCharacter == '\r') || (currentCharacter == '\n'))) + pushLineSeparator(); + if (Character.isWhitespace(currentCharacter)) + return true; + + //buffer the new char which is not a white space + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + //withoutUnicodePtr == 1 is true here + return false; + } catch (IndexOutOfBoundsException e) { + throw new InvalidInputException(INVALID_UNICODE_ESCAPE); + } + } + public final int[] getLineEnds() { + //return a bounded copy of this.lineEnds + + int[] copy; + System.arraycopy(lineEnds, 0, copy = new int[linePtr + 1], 0, linePtr + 1); + return copy; + } + + public char[] getSource() { + return this.source; + } + final char[] optimizedCurrentTokenSource1() { + //return always the same char[] build only once + + //optimization at no speed cost of 99.5 % of the singleCharIdentifier + char charOne = source[startPosition]; + switch (charOne) { + case 'a' : + return charArray_a; + case 'b' : + return charArray_b; + case 'c' : + return charArray_c; + case 'd' : + return charArray_d; + case 'e' : + return charArray_e; + case 'f' : + return charArray_f; + case 'g' : + return charArray_g; + case 'h' : + return charArray_h; + case 'i' : + return charArray_i; + case 'j' : + return charArray_j; + case 'k' : + return charArray_k; + case 'l' : + return charArray_l; + case 'm' : + return charArray_m; + case 'n' : + return charArray_n; + case 'o' : + return charArray_o; + case 'p' : + return charArray_p; + case 'q' : + return charArray_q; + case 'r' : + return charArray_r; + case 's' : + return charArray_s; + case 't' : + return charArray_t; + case 'u' : + return charArray_u; + case 'v' : + return charArray_v; + case 'w' : + return charArray_w; + case 'x' : + return charArray_x; + case 'y' : + return charArray_y; + case 'z' : + return charArray_z; + default : + return new char[] { charOne }; + } + } + final char[] optimizedCurrentTokenSource2() { + //try to return the same char[] build only once + + char c0, c1; + int hash = (((c0 = source[startPosition]) << 6) + (c1 = source[startPosition + 1])) % TableSize; + char[][] table = charArray_length[0][hash]; + int i = newEntry2; + while (++i < InternalTableSize) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) && (c1 == charArray[1])) + return charArray; + } + //---------other side--------- + i = -1; + int max = newEntry2; + while (++i <= max) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) && (c1 == charArray[1])) + return charArray; + } + //--------add the entry------- + if (++max >= InternalTableSize) + max = 0; + char[] r; + table[max] = (r = new char[] { c0, c1 }); + newEntry2 = max; + return r; + } + final char[] optimizedCurrentTokenSource3() { + //try to return the same char[] build only once + + char c0, c1, c2; + int hash = + (((c0 = source[startPosition]) << 12) + ((c1 = source[startPosition + 1]) << 6) + (c2 = source[startPosition + 2])) + % TableSize; + char[][] table = charArray_length[1][hash]; + int i = newEntry3; + while (++i < InternalTableSize) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2])) + return charArray; + } + //---------other side--------- + i = -1; + int max = newEntry3; + while (++i <= max) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2])) + return charArray; + } + //--------add the entry------- + if (++max >= InternalTableSize) + max = 0; + char[] r; + table[max] = (r = new char[] { c0, c1, c2 }); + newEntry3 = max; + return r; + } + final char[] optimizedCurrentTokenSource4() { + //try to return the same char[] build only once + + char c0, c1, c2, c3; + long hash = + ((((long) (c0 = source[startPosition])) << 18) + + ((c1 = source[startPosition + 1]) << 12) + + ((c2 = source[startPosition + 2]) << 6) + + (c3 = source[startPosition + 3])) + % TableSize; + char[][] table = charArray_length[2][(int) hash]; + int i = newEntry4; + while (++i < InternalTableSize) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]) && (c3 == charArray[3])) + return charArray; + } + //---------other side--------- + i = -1; + int max = newEntry4; + while (++i <= max) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]) && (c3 == charArray[3])) + return charArray; + } + //--------add the entry------- + if (++max >= InternalTableSize) + max = 0; + char[] r; + table[max] = (r = new char[] { c0, c1, c2, c3 }); + newEntry4 = max; + return r; + + } + final char[] optimizedCurrentTokenSource5() { + //try to return the same char[] build only once + + char c0, c1, c2, c3, c4; + long hash = + ((((long) (c0 = source[startPosition])) << 24) + + (((long) (c1 = source[startPosition + 1])) << 18) + + ((c2 = source[startPosition + 2]) << 12) + + ((c3 = source[startPosition + 3]) << 6) + + (c4 = source[startPosition + 4])) + % TableSize; + char[][] table = charArray_length[3][(int) hash]; + int i = newEntry5; + while (++i < InternalTableSize) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]) && (c3 == charArray[3]) && (c4 == charArray[4])) + return charArray; + } + //---------other side--------- + i = -1; + int max = newEntry5; + while (++i <= max) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]) && (c3 == charArray[3]) && (c4 == charArray[4])) + return charArray; + } + //--------add the entry------- + if (++max >= InternalTableSize) + max = 0; + char[] r; + table[max] = (r = new char[] { c0, c1, c2, c3, c4 }); + newEntry5 = max; + return r; + + } + final char[] optimizedCurrentTokenSource6() { + //try to return the same char[] build only once + + char c0, c1, c2, c3, c4, c5; + long hash = + ((((long) (c0 = source[startPosition])) << 32) + + (((long) (c1 = source[startPosition + 1])) << 24) + + (((long) (c2 = source[startPosition + 2])) << 18) + + ((c3 = source[startPosition + 3]) << 12) + + ((c4 = source[startPosition + 4]) << 6) + + (c5 = source[startPosition + 5])) + % TableSize; + char[][] table = charArray_length[4][(int) hash]; + int i = newEntry6; + while (++i < InternalTableSize) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) + && (c1 == charArray[1]) + && (c2 == charArray[2]) + && (c3 == charArray[3]) + && (c4 == charArray[4]) + && (c5 == charArray[5])) + return charArray; + } + //---------other side--------- + i = -1; + int max = newEntry6; + while (++i <= max) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) + && (c1 == charArray[1]) + && (c2 == charArray[2]) + && (c3 == charArray[3]) + && (c4 == charArray[4]) + && (c5 == charArray[5])) + return charArray; + } + //--------add the entry------- + if (++max >= InternalTableSize) + max = 0; + char[] r; + table[max] = (r = new char[] { c0, c1, c2, c3, c4, c5 }); + newEntry6 = max; + return r; + } + public final void pushLineSeparator() throws InvalidInputException { + //see comment on isLineDelimiter(char) for the use of '\n' and '\r' + final int INCREMENT = 250; + + if (this.checkNonExternalizedStringLiterals) { + // reinitialize the current line for non externalize strings purpose + currentLine = null; + } + //currentCharacter is at position currentPosition-1 + + // cr 000D + if (currentCharacter == '\r') { + int separatorPos = currentPosition - 1; + if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos)) + return; + //System.out.println("CR-" + separatorPos); + try { + lineEnds[++linePtr] = separatorPos; + } catch (IndexOutOfBoundsException e) { + //linePtr value is correct + int oldLength = lineEnds.length; + int[] old = lineEnds; + lineEnds = new int[oldLength + INCREMENT]; + System.arraycopy(old, 0, lineEnds, 0, oldLength); + lineEnds[linePtr] = separatorPos; + } + // look-ahead for merged cr+lf + try { + if (source[currentPosition] == '\n') { + //System.out.println("look-ahead LF-" + currentPosition); + lineEnds[linePtr] = currentPosition; + currentPosition++; + wasAcr = false; + } else { + wasAcr = true; + } + } catch (IndexOutOfBoundsException e) { + wasAcr = true; + } + } else { + // lf 000A + if (currentCharacter == '\n') { //must merge eventual cr followed by lf + if (wasAcr && (lineEnds[linePtr] == (currentPosition - 2))) { + //System.out.println("merge LF-" + (currentPosition - 1)); + lineEnds[linePtr] = currentPosition - 1; + } else { + int separatorPos = currentPosition - 1; + if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos)) + return; + // System.out.println("LF-" + separatorPos); + try { + lineEnds[++linePtr] = separatorPos; + } catch (IndexOutOfBoundsException e) { + //linePtr value is correct + int oldLength = lineEnds.length; + int[] old = lineEnds; + lineEnds = new int[oldLength + INCREMENT]; + System.arraycopy(old, 0, lineEnds, 0, oldLength); + lineEnds[linePtr] = separatorPos; + } + } + wasAcr = false; + } + } + } + public final void pushUnicodeLineSeparator() { + // isUnicode means that the \r or \n has been read as a unicode character + + //see comment on isLineDelimiter(char) for the use of '\n' and '\r' + + final int INCREMENT = 250; + //currentCharacter is at position currentPosition-1 + + if (this.checkNonExternalizedStringLiterals) { + // reinitialize the current line for non externalize strings purpose + currentLine = null; + } + + // cr 000D + if (currentCharacter == '\r') { + int separatorPos = currentPosition - 6; + if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos)) + return; + //System.out.println("CR-" + separatorPos); + try { + lineEnds[++linePtr] = separatorPos; + } catch (IndexOutOfBoundsException e) { + //linePtr value is correct + int oldLength = lineEnds.length; + int[] old = lineEnds; + lineEnds = new int[oldLength + INCREMENT]; + System.arraycopy(old, 0, lineEnds, 0, oldLength); + lineEnds[linePtr] = separatorPos; + } + // look-ahead for merged cr+lf + if (source[currentPosition] == '\n') { + //System.out.println("look-ahead LF-" + currentPosition); + lineEnds[linePtr] = currentPosition; + currentPosition++; + wasAcr = false; + } else { + wasAcr = true; + } + } else { + // lf 000A + if (currentCharacter == '\n') { //must merge eventual cr followed by lf + if (wasAcr && (lineEnds[linePtr] == (currentPosition - 7))) { + //System.out.println("merge LF-" + (currentPosition - 1)); + lineEnds[linePtr] = currentPosition - 6; + } else { + int separatorPos = currentPosition - 6; + if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos)) + return; + // System.out.println("LF-" + separatorPos); + try { + lineEnds[++linePtr] = separatorPos; + } catch (IndexOutOfBoundsException e) { + //linePtr value is correct + int oldLength = lineEnds.length; + int[] old = lineEnds; + lineEnds = new int[oldLength + INCREMENT]; + System.arraycopy(old, 0, lineEnds, 0, oldLength); + lineEnds[linePtr] = separatorPos; + } + } + wasAcr = false; + } + } + } + public final void recordComment(boolean isJavadoc) { + + // a new annotation comment is recorded + try { + commentStops[++commentPtr] = isJavadoc ? currentPosition : -currentPosition; + } catch (IndexOutOfBoundsException e) { + int oldStackLength = commentStops.length; + int[] oldStack = commentStops; + commentStops = new int[oldStackLength + 30]; + System.arraycopy(oldStack, 0, commentStops, 0, oldStackLength); + commentStops[commentPtr] = isJavadoc ? currentPosition : -currentPosition; + //grows the positions buffers too + int[] old = commentStarts; + commentStarts = new int[oldStackLength + 30]; + System.arraycopy(old, 0, commentStarts, 0, oldStackLength); + } + + //the buffer is of a correct size here + commentStarts[commentPtr] = startPosition; + } + public void resetTo(int begin, int end) { + //reset the scanner to a given position where it may rescan again + + diet = false; + initialPosition = startPosition = currentPosition = begin; + eofPosition = end < Integer.MAX_VALUE ? end + 1 : end; + commentPtr = -1; // reset comment stack + } + + public final void scanEscapeCharacter() throws InvalidInputException { + // the string with "\\u" is a legal string of two chars \ and u + //thus we use a direct access to the source (for regular cases). + + if (unicodeAsBackSlash) { + // consume next character + unicodeAsBackSlash = false; + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (withoutUnicodePtr != 0) { + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + } + } else + currentCharacter = source[currentPosition++]; + switch (currentCharacter) { + case 'b' : + currentCharacter = '\b'; + break; + case 't' : + currentCharacter = '\t'; + break; + case 'n' : + currentCharacter = '\n'; + break; + case 'f' : + currentCharacter = '\f'; + break; + case 'r' : + currentCharacter = '\r'; + break; + case '\"' : + currentCharacter = '\"'; + break; + case '\'' : + currentCharacter = '\''; + break; + case '\\' : + currentCharacter = '\\'; + break; + default : + // -----------octal escape-------------- + // OctalDigit + // OctalDigit OctalDigit + // ZeroToThree OctalDigit OctalDigit + + int number = Character.getNumericValue(currentCharacter); + if (number >= 0 && number <= 7) { + boolean zeroToThreeNot = number > 3; + if (Character.isDigit(currentCharacter = source[currentPosition++])) { + int digit = Character.getNumericValue(currentCharacter); + if (digit >= 0 && digit <= 7) { + number = (number * 8) + digit; + if (Character.isDigit(currentCharacter = source[currentPosition++])) { + if (zeroToThreeNot) { // has read \NotZeroToThree OctalDigit Digit --> ignore last character + currentPosition--; + } else { + digit = Character.getNumericValue(currentCharacter); + if (digit >= 0 && digit <= 7) { // has read \ZeroToThree OctalDigit OctalDigit + number = (number * 8) + digit; + } else { // has read \ZeroToThree OctalDigit NonOctalDigit --> ignore last character + currentPosition--; + } + } + } else { // has read \OctalDigit NonDigit--> ignore last character + currentPosition--; + } + } else { // has read \OctalDigit NonOctalDigit--> ignore last character + currentPosition--; + } + } else { // has read \OctalDigit --> ignore last character + currentPosition--; + } + if (number > 255) + throw new InvalidInputException(INVALID_ESCAPE); + currentCharacter = (char) number; + } else + throw new InvalidInputException(INVALID_ESCAPE); + } + } + public int scanIdentifierOrKeyword() throws InvalidInputException { + //test keywords + + //first dispatch on the first char. + //then the length. If there are several + //keywors with the same length AND the same first char, then do another + //disptach on the second char :-)...cool....but fast ! + useAssertAsAnIndentifier = false; + while (getNextCharAsJavaIdentifierPart()) { + }; + + int index, length; + char[] data; + char firstLetter; + if (withoutUnicodePtr == 0) + + //quick test on length == 1 but not on length > 12 while most identifier + //have a length which is <= 12...but there are lots of identifier with + //only one char.... + + { + if ((length = currentPosition - startPosition) == 1) + return TokenNameIdentifier; + data = source; + index = startPosition; + } else { + if ((length = withoutUnicodePtr) == 1) + return TokenNameIdentifier; + data = withoutUnicodeBuffer; + index = 1; + } + + firstLetter = data[index]; + switch (firstLetter) { + + case 'a' : // as and array + switch (length) { + case 2 : //as + if ((data[++index] == 's')) { + return TokenNameas; + } else { + return TokenNameIdentifier; + } + case 3 : //and + if ((data[++index] == 'n') && (data[++index] == 'd')) { + return TokenNameas; + } else { + return TokenNameIdentifier; + } + // case 5 : + // if ((data[++index] == 'r') && (data[++index] == 'r') && (data[++index] == 'a') && (data[++index] == 'y')) + // return TokenNamearray; + // else + // return TokenNameIdentifier; + default : + return TokenNameIdentifier; + } + case 'b' : //break + switch (length) { + case 5 : + if ((data[++index] == 'r') && (data[++index] == 'e') && (data[++index] == 'a') && (data[++index] == 'k')) + return TokenNamebreak; + else + return TokenNameIdentifier; + default : + return TokenNameIdentifier; + } + + case 'c' : //case class continue + switch (length) { + case 4 : + if ((data[++index] == 'a') && (data[++index] == 's') && (data[++index] == 'e')) + return TokenNamecase; + else + return TokenNameIdentifier; + case 5 : + if ((data[index] == 'l') && (data[++index] == 'a') && (data[++index] == 's') && (data[++index] == 's')) + return TokenNameclass; + else + return TokenNameIdentifier; + case 8 : + if ((data[++index] == 'o') + && (data[++index] == 'n') + && (data[++index] == 't') + && (data[++index] == 'i') + && (data[++index] == 'n') + && (data[++index] == 'u') + && (data[++index] == 'e')) + return TokenNamecontinue; + else + return TokenNameIdentifier; + default : + return TokenNameIdentifier; + } + + case 'd' : //define default do + switch (length) { + case 2 : + if ((data[++index] == 'o')) + return TokenNamedo; + else + return TokenNameIdentifier; + case 6 : + if ((data[++index] == 'e') + && (data[++index] == 'f') + && (data[++index] == 'i') + && (data[++index] == 'n') + && (data[++index] == 'e')) + return TokenNamedefine; + else + return TokenNameIdentifier; + case 7 : + if ((data[++index] == 'e') + && (data[++index] == 'f') + && (data[++index] == 'a') + && (data[++index] == 'u') + && (data[++index] == 'l') + && (data[++index] == 't')) + return TokenNamedefault; + else + return TokenNameIdentifier; + default : + return TokenNameIdentifier; + } + case 'e' : //echo else elseif extends + switch (length) { + case 4 : + if ((data[++index] == 'c') && (data[++index] == 'h') && (data[++index] == 'o')) + return TokenNameecho; + else if ((data[++index] == 'l') && (data[++index] == 's') && (data[++index] == 'e')) + return TokenNameelse; + else + return TokenNameIdentifier; + case 5 : // endif + if ((data[++index] == 'n') && (data[++index] == 'd') && (data[++index] == 'i') && (data[++index] == 'f')) + return TokenNameendif; + else + return TokenNameIdentifier; + case 6 : // endfor + if ((data[++index] == 'n') + && (data[++index] == 'd') + && (data[++index] == 'f') + && (data[++index] == 'o') + && (data[++index] == 'r')) + return TokenNameendfor; + else if ( + (data[++index] == 'l') + && (data[++index] == 's') + && (data[++index] == 'e') + && (data[++index] == 'i') + && (data[++index] == 'f')) + return TokenNameelseif; + else + return TokenNameIdentifier; + case 7 : + if ((data[++index] == 'x') + && (data[++index] == 't') + && (data[++index] == 'e') + && (data[++index] == 'n') + && (data[++index] == 'd') + && (data[++index] == 's')) + return TokenNameextends; + else + return TokenNameIdentifier; + case 8 : // endwhile + if ((data[++index] == 'n') + && (data[++index] == 'd') + && (data[++index] == 'w') + && (data[++index] == 'h') + && (data[++index] == 'i') + && (data[++index] == 'l') + && (data[++index] == 'e')) + return TokenNameendwhile; + else + return TokenNameIdentifier; + case 9 : // endswitch + if ((data[++index] == 'n') + && (data[++index] == 'd') + && (data[++index] == 's') + && (data[++index] == 'w') + && (data[++index] == 'i') + && (data[++index] == 't') + && (data[++index] == 'c') + && (data[++index] == 'h')) + return TokenNameendswitch; + else + return TokenNameIdentifier; + case 10 : // endforeach + if ((data[++index] == 'n') + && (data[++index] == 'd') + && (data[++index] == 'f') + && (data[++index] == 'o') + && (data[++index] == 'r') + && (data[++index] == 'e') + && (data[++index] == 'a') + && (data[++index] == 'c') + && (data[++index] == 'h')) + return TokenNameendforeach; + else + return TokenNameIdentifier; + + default : + return TokenNameIdentifier; + } + + case 'f' : //for false function + switch (length) { + case 3 : + if ((data[++index] == 'o') && (data[++index] == 'r')) + return TokenNamefor; + else + return TokenNameIdentifier; + case 5 : + if ((data[index] == 'a') && (data[++index] == 'l') && (data[++index] == 's') && (data[++index] == 'e')) + return TokenNamefalse; + else + return TokenNameIdentifier; + case 8 : // function + if ((data[index] == 'u') + && (data[++index] == 'n') + && (data[++index] == 'c') + && (data[++index] == 't') + && (data[++index] == 'i') + && (data[++index] == 'o') + && (data[++index] == 'n')) + return TokenNamefunction; + else + return TokenNameIdentifier; + default : + return TokenNameIdentifier; + } + case 'g' : //global + if (length == 6) { + if ((data[++index] == 'l') + && (data[++index] == 'o') + && (data[++index] == 'b') + && (data[++index] == 'a') + && (data[++index] == 'l')) { + return TokenNameglobal; + } + } + return TokenNameIdentifier; + + case 'i' : //if int + switch (length) { + case 2 : + if (data[++index] == 'f') + return TokenNameif; + else + return TokenNameIdentifier; + // case 3 : + // if ((data[++index] == 'n') && (data[++index] == 't')) + // return TokenNameint; + // else + // return TokenNameIdentifier; + case 7 : + if ((data[++index] == 'n') + && (data[++index] == 'c') + && (data[++index] == 'l') + && (data[++index] == 'u') + && (data[++index] == 'd') + && (data[++index] == 'e')) + return TokenNameinclude; + else + return TokenNameIdentifier; + case 12 : + if ((data[++index] == 'n') + && (data[++index] == 'c') + && (data[++index] == 'l') + && (data[++index] == 'u') + && (data[++index] == 'd') + && (data[++index] == 'e') + && (data[++index] == '_') + && (data[++index] == 'o') + && (data[++index] == 'n') + && (data[++index] == 'c') + && (data[++index] == 'e')) + return TokenNameinclude_once; + else + return TokenNameIdentifier; + default : + return TokenNameIdentifier; + } + + case 'l' : //list + if (length == 4) { + if ((data[++index] == 'i') && (data[++index] == 's') && (data[++index] == 't')) { + return TokenNamelist; + } + } + return TokenNameIdentifier; + + case 'n' : // new null + switch (length) { + case 3 : + if ((data[++index] == 'e') && (data[++index] == 'w')) + return TokenNamenew; + else + return TokenNameIdentifier; + case 4 : + if ((data[++index] == 'u') && (data[++index] == 'l') && (data[++index] == 'l')) + return TokenNamenull; + else + return TokenNameIdentifier; + + default : + return TokenNameIdentifier; + } + case 'o' : // or old_function + if (length == 2) { + if (data[++index] == 'r') { + return TokenNameor; + } + } +// if (length == 12) { +// if ((data[++index] == 'l') +// && (data[++index] == 'd') +// && (data[++index] == '_') +// && (data[++index] == 'f') +// && (data[++index] == 'u') +// && (data[++index] == 'n') +// && (data[++index] == 'c') +// && (data[++index] == 't') +// && (data[++index] == 'i') +// && (data[++index] == 'o') +// && (data[++index] == 'n')) { +// return TokenNameold_function; +// } +// } + return TokenNameIdentifier; + + case 'p' : // print + if (length == 5) { + if ((data[++index] == 'r') && (data[++index] == 'i') && (data[++index] == 'n') && (data[++index] == 't')) { + return TokenNameprint; + } + } + return TokenNameIdentifier; + case 'r' : //return require require_once + if (length == 6) { + if ((data[++index] == 'e') + && (data[++index] == 't') + && (data[++index] == 'u') + && (data[++index] == 'r') + && (data[++index] == 'n')) { + return TokenNamereturn; + } + } else if (length == 7) { + if ((data[++index] == 'e') + && (data[++index] == 'q') + && (data[++index] == 'u') + && (data[++index] == 'i') + && (data[++index] == 'r') + && (data[++index] == 'e')) { + return TokenNamerequire; + } + } else if (length == 12) { + if ((data[++index] == 'e') + && (data[++index] == 'q') + && (data[++index] == 'u') + && (data[++index] == 'i') + && (data[++index] == 'r') + && (data[++index] == 'e') + && (data[++index] == '_') + && (data[++index] == 'o') + && (data[++index] == 'n') + && (data[++index] == 'c') + && (data[++index] == 'e')) { + return TokenNamerequire_once; + } + } else + return TokenNameIdentifier; + + case 's' : //static switch + switch (length) { + case 6 : + if (data[++index] == 't') + if ((data[++index] == 'a') && (data[++index] == 't') && (data[++index] == 'i') && (data[++index] == 'c')) { + return TokenNamestatic; + } else + return TokenNameIdentifier; + else if ( + (data[index] == 'w') + && (data[++index] == 'i') + && (data[++index] == 't') + && (data[++index] == 'c') + && (data[++index] == 'h')) + return TokenNameswitch; + else + return TokenNameIdentifier; + default : + return TokenNameIdentifier; + } + + case 't' : // true + switch (length) { + + case 4 : + if ((data[index] == 'r') && (data[++index] == 'u') && (data[++index] == 'e')) + return TokenNametrue; + else + return TokenNameIdentifier; + // if ((data[++index] == 'h') && (data[++index] == 'i') && (data[++index] == 's')) + // return TokenNamethis; + + default : + return TokenNameIdentifier; + } + + case 'v' : //void volatile + switch (length) { + case 3 : + if ((data[++index] == 'a') && (data[++index] == 'r')) + return TokenNamevar; + else + return TokenNameIdentifier; + + default : + return TokenNameIdentifier; + } + + case 'w' : //while widefp + switch (length) { + case 5 : + if ((data[++index] == 'h') && (data[++index] == 'i') && (data[++index] == 'l') && (data[++index] == 'e')) + return TokenNamewhile; + else + return TokenNameIdentifier; + //case 6:if ( (data[++index] =='i') && (data[++index]=='d') && (data[++index]=='e') && (data[++index]=='f')&& (data[++index]=='p')) + //return TokenNamewidefp ; + //else + //return TokenNameIdentifier; + default : + return TokenNameIdentifier; + } + + case 'x' : //xor + switch (length) { + case 3 : + if ((data[++index] == 'o') && (data[++index] == 'r')) + return TokenNamexor; + else + return TokenNameIdentifier; + + default : + return TokenNameIdentifier; + } + default : + return TokenNameIdentifier; + } + } + public int scanNumber(boolean dotPrefix) throws InvalidInputException { + + //when entering this method the currentCharacter is the firt + //digit of the number , i.e. it may be preceeded by a . when + //dotPrefix is true + + boolean floating = dotPrefix; + if ((!dotPrefix) && (currentCharacter == '0')) { + if (getNextChar('x', 'X') >= 0) { //----------hexa----------------- + //force the first char of the hexa number do exist... + // consume next character + unicodeAsBackSlash = false; + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (withoutUnicodePtr != 0) { + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + } + if (Character.digit(currentCharacter, 16) == -1) + throw new InvalidInputException(INVALID_HEXA); + //---end forcing-- + while (getNextCharAsDigit(16)) { + }; + if (getNextChar('l', 'L') >= 0) + return TokenNameLongLiteral; + else + return TokenNameIntegerLiteral; + } + + //there is x or X in the number + //potential octal ! ... some one may write 000099.0 ! thus 00100 < 00078.0 is true !!!!! crazy language + if (getNextCharAsDigit()) { //-------------potential octal----------------- + while (getNextCharAsDigit()) { + }; + + if (getNextChar('l', 'L') >= 0) { + return TokenNameLongLiteral; + } + + if (getNextChar('f', 'F') >= 0) { + return TokenNameFloatingPointLiteral; + } + + if (getNextChar('d', 'D') >= 0) { + return TokenNameDoubleLiteral; + } else { //make the distinction between octal and float .... + if (getNextChar('.')) { //bingo ! .... + while (getNextCharAsDigit()) { + }; + if (getNextChar('e', 'E') >= 0) { // consume next character + unicodeAsBackSlash = false; + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (withoutUnicodePtr != 0) { + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + } + + if ((currentCharacter == '-') || (currentCharacter == '+')) { // consume next character + unicodeAsBackSlash = false; + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (withoutUnicodePtr != 0) { + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + } + } + if (!Character.isDigit(currentCharacter)) + throw new InvalidInputException(INVALID_FLOAT); + while (getNextCharAsDigit()) { + }; + } + if (getNextChar('f', 'F') >= 0) + return TokenNameFloatingPointLiteral; + getNextChar('d', 'D'); //jump over potential d or D + return TokenNameDoubleLiteral; + } else { + return TokenNameIntegerLiteral; + } + } + } else { + /* carry on */ + } + } + + while (getNextCharAsDigit()) { + }; + + if ((!dotPrefix) && (getNextChar('l', 'L') >= 0)) + return TokenNameLongLiteral; + + if ((!dotPrefix) && (getNextChar('.'))) { //decimal part that can be empty + while (getNextCharAsDigit()) { + }; + floating = true; + } + + //if floating is true both exponant and suffix may be optional + + if (getNextChar('e', 'E') >= 0) { + floating = true; + // consume next character + unicodeAsBackSlash = false; + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (withoutUnicodePtr != 0) { + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + } + + if ((currentCharacter == '-') || (currentCharacter == '+')) { // consume next character + unicodeAsBackSlash = false; + if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (withoutUnicodePtr != 0) { + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + } + } + if (!Character.isDigit(currentCharacter)) + throw new InvalidInputException(INVALID_FLOAT); + while (getNextCharAsDigit()) { + }; + } + + if (getNextChar('d', 'D') >= 0) + return TokenNameDoubleLiteral; + if (getNextChar('f', 'F') >= 0) + return TokenNameFloatingPointLiteral; + + //the long flag has been tested before + + return floating ? TokenNameDoubleLiteral : TokenNameIntegerLiteral; + } + /** + * Search the line number corresponding to a specific position + * + */ + public final int getLineNumber(int position) { + + if (lineEnds == null) + return 1; + int length = linePtr + 1; + if (length == 0) + return 1; + int g = 0, d = length - 1; + int m = 0; + while (g <= d) { + m = (g + d) / 2; + if (position < lineEnds[m]) { + d = m - 1; + } else if (position > lineEnds[m]) { + g = m + 1; + } else { + return m + 1; + } + } + if (position < lineEnds[m]) { + return m + 1; + } + return m + 2; + } + public final void setSource(char[] source) { + //the source-buffer is set to sourceString + + if (source == null) { + this.source = new char[0]; + } else { + this.source = source; + } + startPosition = -1; + initialPosition = currentPosition = 0; + containsAssertKeyword = false; + withoutUnicodeBuffer = new char[this.source.length]; + + } + + public String toString() { + if (startPosition == source.length) + return "EOF\n\n" + new String(source); //$NON-NLS-1$ + if (currentPosition > source.length) + return "behind the EOF :-( ....\n\n" + new String(source); //$NON-NLS-1$ + + char front[] = new char[startPosition]; + System.arraycopy(source, 0, front, 0, startPosition); + + int middleLength = (currentPosition - 1) - startPosition + 1; + char middle[]; + if (middleLength > -1) { + middle = new char[middleLength]; + System.arraycopy(source, startPosition, middle, 0, middleLength); + } else { + middle = new char[0]; + } + + char end[] = new char[source.length - (currentPosition - 1)]; + System.arraycopy(source, (currentPosition - 1) + 1, end, 0, source.length - (currentPosition - 1) - 1); + + return new String(front) + "\n===============================\nStarts here -->" //$NON-NLS-1$ + + new String(middle) + "<-- Ends here\n===============================\n" //$NON-NLS-1$ + + new String(end); + } + public final String toStringAction(int act) { + switch (act) { + case TokenNameIdentifier : + return "Identifier(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + // case TokenNameabstract : + // return "abstract"; //$NON-NLS-1$ + // case TokenNameboolean : + // return "boolean"; //$NON-NLS-1$ + case TokenNamebreak : + return "break"; //$NON-NLS-1$ + // case TokenNamebyte : + // return "byte"; //$NON-NLS-1$ + case TokenNamecase : + return "case"; //$NON-NLS-1$ + // case TokenNamecatch : + // return "catch"; //$NON-NLS-1$ + // case TokenNamechar : + // return "char"; //$NON-NLS-1$ + case TokenNameclass : + return "class"; //$NON-NLS-1$ + case TokenNamecontinue : + return "continue"; //$NON-NLS-1$ + case TokenNamedefault : + return "default"; //$NON-NLS-1$ + case TokenNamedo : + return "do"; //$NON-NLS-1$ + // case TokenNamedouble : + // return "double"; //$NON-NLS-1$ + case TokenNameelse : + return "else"; //$NON-NLS-1$ + case TokenNameextends : + return "extends"; //$NON-NLS-1$ + case TokenNamefalse : + return "false"; //$NON-NLS-1$ + // case TokenNamefinal : + // return "final"; //$NON-NLS-1$ + // case TokenNamefinally : + // return "finally"; //$NON-NLS-1$ + // case TokenNamefloat : + // return "float"; //$NON-NLS-1$ + case TokenNamefor : + return "for"; //$NON-NLS-1$ + case TokenNameif : + return "if"; //$NON-NLS-1$ + // case TokenNameimplements : + // return "implements"; //$NON-NLS-1$ + // case TokenNameimport : + // return "import"; //$NON-NLS-1$ + // case TokenNameinstanceof : + // return "instanceof"; //$NON-NLS-1$ + // case TokenNameint : + // return "int"; //$NON-NLS-1$ + // case TokenNameinterface : + // return "interface"; //$NON-NLS-1$ + // case TokenNamelong : + // return "long"; //$NON-NLS-1$ + // case TokenNamenative : + // return "native"; //$NON-NLS-1$ + case TokenNamenew : + return "new"; //$NON-NLS-1$ + case TokenNamenull : + return "null"; //$NON-NLS-1$ + // case TokenNamepackage : + // return "package"; //$NON-NLS-1$ + // case TokenNameprivate : + // return "private"; //$NON-NLS-1$ + // case TokenNameprotected : + // return "protected"; //$NON-NLS-1$ + // case TokenNamepublic : + // return "public"; //$NON-NLS-1$ + case TokenNamereturn : + return "return"; //$NON-NLS-1$ + // case TokenNameshort : + // return "short"; //$NON-NLS-1$ + case TokenNamestatic : + return "static"; //$NON-NLS-1$ + // case TokenNamesuper : + // return "super"; //$NON-NLS-1$ + case TokenNameswitch : + return "switch"; //$NON-NLS-1$ + // case TokenNamesynchronized : + // return "synchronized"; //$NON-NLS-1$ + // case TokenNamethis : + // return "this"; //$NON-NLS-1$ + // case TokenNamethrow : + // return "throw"; //$NON-NLS-1$ + // case TokenNamethrows : + // return "throws"; //$NON-NLS-1$ + // case TokenNametransient : + // return "transient"; //$NON-NLS-1$ + case TokenNametrue : + return "true"; //$NON-NLS-1$ + // case TokenNametry : + // return "try"; //$NON-NLS-1$ + // case TokenNamevoid : + // return "void"; //$NON-NLS-1$ + // case TokenNamevolatile : + // return "volatile"; //$NON-NLS-1$ + case TokenNamewhile : + return "while"; //$NON-NLS-1$ + + case TokenNameIntegerLiteral : + return "Integer(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + case TokenNameLongLiteral : + return "Long(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + case TokenNameFloatingPointLiteral : + return "Float(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + case TokenNameDoubleLiteral : + return "Double(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + case TokenNameCharacterLiteral : + return "Char(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + case TokenNameStringLiteral : + return "String(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + + case TokenNamePLUS_PLUS : + return "++"; //$NON-NLS-1$ + case TokenNameMINUS_MINUS : + return "--"; //$NON-NLS-1$ + case TokenNameEQUAL_EQUAL : + return "=="; //$NON-NLS-1$ + case TokenNameLESS_EQUAL : + return "<="; //$NON-NLS-1$ + case TokenNameGREATER_EQUAL : + return ">="; //$NON-NLS-1$ + case TokenNameNOT_EQUAL : + return "!="; //$NON-NLS-1$ + case TokenNameLEFT_SHIFT : + return "<<"; //$NON-NLS-1$ + case TokenNameRIGHT_SHIFT : + return ">>"; //$NON-NLS-1$ + case TokenNameUNSIGNED_RIGHT_SHIFT : + return ">>>"; //$NON-NLS-1$ + case TokenNamePLUS_EQUAL : + return "+="; //$NON-NLS-1$ + case TokenNameMINUS_EQUAL : + return "-="; //$NON-NLS-1$ + case TokenNameMULTIPLY_EQUAL : + return "*="; //$NON-NLS-1$ + case TokenNameDIVIDE_EQUAL : + return "/="; //$NON-NLS-1$ + case TokenNameAND_EQUAL : + return "&="; //$NON-NLS-1$ + case TokenNameOR_EQUAL : + return "|="; //$NON-NLS-1$ + case TokenNameXOR_EQUAL : + return "^="; //$NON-NLS-1$ + case TokenNameREMAINDER_EQUAL : + return "%="; //$NON-NLS-1$ + case TokenNameLEFT_SHIFT_EQUAL : + return "<<="; //$NON-NLS-1$ + case TokenNameRIGHT_SHIFT_EQUAL : + return ">>="; //$NON-NLS-1$ + case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : + return ">>>="; //$NON-NLS-1$ + case TokenNameOR_OR : + return "||"; //$NON-NLS-1$ + case TokenNameAND_AND : + return "&&"; //$NON-NLS-1$ + case TokenNamePLUS : + return "+"; //$NON-NLS-1$ + case TokenNameMINUS : + return "-"; //$NON-NLS-1$ + case TokenNameNOT : + return "!"; //$NON-NLS-1$ + case TokenNameREMAINDER : + return "%"; //$NON-NLS-1$ + case TokenNameXOR : + return "^"; //$NON-NLS-1$ + case TokenNameAND : + return "&"; //$NON-NLS-1$ + case TokenNameMULTIPLY : + return "*"; //$NON-NLS-1$ + case TokenNameOR : + return "|"; //$NON-NLS-1$ + case TokenNameTWIDDLE : + return "~"; //$NON-NLS-1$ + case TokenNameDIVIDE : + return "/"; //$NON-NLS-1$ + case TokenNameGREATER : + return ">"; //$NON-NLS-1$ + case TokenNameLESS : + return "<"; //$NON-NLS-1$ + case TokenNameLPAREN : + return "("; //$NON-NLS-1$ + case TokenNameRPAREN : + return ")"; //$NON-NLS-1$ + case TokenNameLBRACE : + return "{"; //$NON-NLS-1$ + case TokenNameRBRACE : + return "}"; //$NON-NLS-1$ + case TokenNameLBRACKET : + return "["; //$NON-NLS-1$ + case TokenNameRBRACKET : + return "]"; //$NON-NLS-1$ + case TokenNameSEMICOLON : + return ";"; //$NON-NLS-1$ + case TokenNameQUESTION : + return "?"; //$NON-NLS-1$ + case TokenNameCOLON : + return ":"; //$NON-NLS-1$ + case TokenNameCOMMA : + return ","; //$NON-NLS-1$ + case TokenNameDOT : + return "."; //$NON-NLS-1$ + case TokenNameEQUAL : + return "="; //$NON-NLS-1$ + case TokenNameEOF : + return "EOF"; //$NON-NLS-1$ + default : + return "not-a-token"; //$NON-NLS-1$ + } + } + + public Scanner(boolean tokenizeComments, boolean tokenizeWhiteSpace, boolean checkNonExternalizedStringLiterals) { + this(tokenizeComments, tokenizeWhiteSpace, checkNonExternalizedStringLiterals, false); + } + + public Scanner( + boolean tokenizeComments, + boolean tokenizeWhiteSpace, + boolean checkNonExternalizedStringLiterals, + boolean assertMode) { + this.eofPosition = Integer.MAX_VALUE; + this.tokenizeComments = tokenizeComments; + this.tokenizeWhiteSpace = tokenizeWhiteSpace; + this.checkNonExternalizedStringLiterals = checkNonExternalizedStringLiterals; + this.assertMode = assertMode; + } + + private void checkNonExternalizeString() throws InvalidInputException { + if (currentLine == null) + return; + parseTags(currentLine); + } + + private void parseTags(NLSLine line) throws InvalidInputException { + String s = new String(getCurrentTokenSource()); + int pos = s.indexOf(TAG_PREFIX); + int lineLength = line.size(); + while (pos != -1) { + int start = pos + TAG_PREFIX_LENGTH; + int end = s.indexOf(TAG_POSTFIX, start); + String index = s.substring(start, end); + int i = 0; + try { + i = Integer.parseInt(index) - 1; // Tags are one based not zero based. + } catch (NumberFormatException e) { + i = -1; // we don't want to consider this as a valid NLS tag + } + if (line.exists(i)) { + line.set(i, null); + } + pos = s.indexOf(TAG_PREFIX, start); + } + + this.nonNLSStrings = new StringLiteral[lineLength]; + int nonNLSCounter = 0; + for (Iterator iterator = line.iterator(); iterator.hasNext();) { + StringLiteral literal = (StringLiteral) iterator.next(); + if (literal != null) { + this.nonNLSStrings[nonNLSCounter++] = literal; + } + } + if (nonNLSCounter == 0) { + this.nonNLSStrings = null; + currentLine = null; + return; + } + this.wasNonExternalizedStringLiteral = true; + if (nonNLSCounter != lineLength) { + System.arraycopy(this.nonNLSStrings, 0, (this.nonNLSStrings = new StringLiteral[nonNLSCounter]), 0, nonNLSCounter); + } + currentLine = null; + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/SourceConstructorDeclaration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/SourceConstructorDeclaration.java new file mode 100644 index 0000000..bc3a7e7 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/SourceConstructorDeclaration.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.parser; + +import net.sourceforge.phpdt.internal.compiler.CompilationResult; +import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration; + +public class SourceConstructorDeclaration extends ConstructorDeclaration { + public int selectorSourceEnd; + + public SourceConstructorDeclaration(CompilationResult compilationResult){ + super(compilationResult); + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/SourceFieldDeclaration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/SourceFieldDeclaration.java new file mode 100644 index 0000000..47dac22 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/SourceFieldDeclaration.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.parser; + +import net.sourceforge.phpdt.internal.compiler.ast.Expression; +import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration; + +public class SourceFieldDeclaration extends FieldDeclaration { + public int fieldEndPosition; +public SourceFieldDeclaration( + Expression initialization, + char[] name, + int sourceStart, + int sourceEnd) { + super(initialization, name, sourceStart, sourceEnd); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/SourceMethodDeclaration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/SourceMethodDeclaration.java new file mode 100644 index 0000000..19ed051 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/SourceMethodDeclaration.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.parser; + +import net.sourceforge.phpdt.internal.compiler.CompilationResult; +import net.sourceforge.phpdt.internal.compiler.ast.MethodDeclaration; + +public class SourceMethodDeclaration extends MethodDeclaration { + public int selectorSourceEnd; + + public SourceMethodDeclaration(CompilationResult compilationResult){ + super(compilationResult); + } + +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/SourceTypeConverter.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/SourceTypeConverter.java new file mode 100644 index 0000000..422c4b8 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/SourceTypeConverter.java @@ -0,0 +1,350 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.parser; + +/** + * Converter from source element type to parsed compilation unit. + * + * Limitation: + * | The source element field does not carry any information for its constant part, thus + * | the converted parse tree will not include any field initializations. + * | Therefore, any binary produced by compiling against converted source elements will + * | not take advantage of remote field constant inlining. + * | Given the intended purpose of the conversion is to resolve references, this is not + * | a problem. + * + */ + +import net.sourceforge.phpdt.internal.compiler.CompilationResult; +import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.Argument; +import net.sourceforge.phpdt.internal.compiler.ast.ArrayQualifiedTypeReference; +import net.sourceforge.phpdt.internal.compiler.ast.ArrayTypeReference; +import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.ImportReference; +import net.sourceforge.phpdt.internal.compiler.ast.MemberTypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.MethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.QualifiedTypeReference; +import net.sourceforge.phpdt.internal.compiler.ast.SingleTypeReference; +import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.TypeReference; +import net.sourceforge.phpdt.internal.compiler.env.ISourceField; +import net.sourceforge.phpdt.internal.compiler.env.ISourceMethod; +import net.sourceforge.phpdt.internal.compiler.env.ISourceType; +import net.sourceforge.phpdt.internal.compiler.lookup.CompilerModifiers; +import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class SourceTypeConverter implements CompilerModifiers { + + /* + * Convert a set of source element types into a parsed compilation unit declaration + * The argument types are then all grouped in the same unit. The argument types must + * at least contain one type. + * Can optionally ignore fields & methods or member types + */ + public static CompilationUnitDeclaration buildCompilationUnit( + ISourceType[] sourceTypes, + boolean needFieldsAndMethods, + boolean needMemberTypes, + ProblemReporter problemReporter, + CompilationResult compilationResult) { + + ISourceType sourceType = sourceTypes[0]; + if (sourceType.getName() == null) + return null; // do a basic test that the sourceType is valid + + CompilationUnitDeclaration compilationUnit = + new CompilationUnitDeclaration(problemReporter, compilationResult, 0); + // not filled at this point + + /* only positions available */ + int start = sourceType.getNameSourceStart(); + int end = sourceType.getNameSourceEnd(); + + /* convert package and imports */ + if (sourceType.getPackageName() != null + && sourceType.getPackageName().length > 0) + // if its null then it is defined in the default package + compilationUnit.currentPackage = + createImportReference(sourceType.getPackageName(), start, end); + char[][] importNames = sourceType.getImports(); + int importCount = importNames == null ? 0 : importNames.length; + compilationUnit.imports = new ImportReference[importCount]; + for (int i = 0; i < importCount; i++) + compilationUnit.imports[i] = createImportReference(importNames[i], start, end); + /* convert type(s) */ + int typeCount = sourceTypes.length; + compilationUnit.types = new TypeDeclaration[typeCount]; + for (int i = 0; i < typeCount; i++) { + compilationUnit.types[i] = + convert(sourceTypes[i], needFieldsAndMethods, needMemberTypes, compilationResult); + } + return compilationUnit; + } + + /* + * Convert a field source element into a parsed field declaration + */ + private static FieldDeclaration convert(ISourceField sourceField) { + + FieldDeclaration field = new FieldDeclaration(); + + int start = sourceField.getNameSourceStart(); + int end = sourceField.getNameSourceEnd(); + + field.name = sourceField.getName(); + field.sourceStart = start; + field.sourceEnd = end; + field.type = createTypeReference(sourceField.getTypeName(), start, end); + field.declarationSourceStart = sourceField.getDeclarationSourceStart(); + field.declarationSourceEnd = sourceField.getDeclarationSourceEnd(); + field.modifiers = sourceField.getModifiers(); + + /* conversion of field constant: if not present, then cannot generate binary against + converted parse nodes */ + /* + if (field.modifiers & AccFinal){ + char[] initializationSource = sourceField.getInitializationSource(); + } + */ + return field; + } + + /* + * Convert a method source element into a parsed method/constructor declaration + */ + private static AbstractMethodDeclaration convert(ISourceMethod sourceMethod, CompilationResult compilationResult) { + + AbstractMethodDeclaration method; + + /* only source positions available */ + int start = sourceMethod.getNameSourceStart(); + int end = sourceMethod.getNameSourceEnd(); + + if (sourceMethod.isConstructor()) { + ConstructorDeclaration decl = new ConstructorDeclaration(compilationResult); + decl.isDefaultConstructor = false; + method = decl; + } else { + MethodDeclaration decl = new MethodDeclaration(compilationResult); + /* convert return type */ + decl.returnType = + createTypeReference(sourceMethod.getReturnTypeName(), start, end); + method = decl; + } + method.selector = sourceMethod.getSelector(); + method.modifiers = sourceMethod.getModifiers(); + method.sourceStart = start; + method.sourceEnd = end; + method.declarationSourceStart = sourceMethod.getDeclarationSourceStart(); + method.declarationSourceEnd = sourceMethod.getDeclarationSourceEnd(); + + /* convert arguments */ + char[][] argumentTypeNames = sourceMethod.getArgumentTypeNames(); + char[][] argumentNames = sourceMethod.getArgumentNames(); + int argumentCount = argumentTypeNames == null ? 0 : argumentTypeNames.length; + long position = (long) start << 32 + end; + method.arguments = new Argument[argumentCount]; + for (int i = 0; i < argumentCount; i++) { + method.arguments[i] = + new Argument( + argumentNames[i], + position, + createTypeReference(argumentTypeNames[i], start, end), + AccDefault); + // do not care whether was final or not + } + + /* convert thrown exceptions */ + char[][] exceptionTypeNames = sourceMethod.getExceptionTypeNames(); + int exceptionCount = exceptionTypeNames == null ? 0 : exceptionTypeNames.length; + method.thrownExceptions = new TypeReference[exceptionCount]; + for (int i = 0; i < exceptionCount; i++) { + method.thrownExceptions[i] = + createTypeReference(exceptionTypeNames[i], start, end); + } + return method; + } + + /* + * Convert a source element type into a parsed type declaration + * + * Can optionally ignore fields & methods + */ + private static TypeDeclaration convert( + ISourceType sourceType, + boolean needFieldsAndMethods, + boolean needMemberTypes, + CompilationResult compilationResult) { + /* create type declaration - can be member type */ + TypeDeclaration type; + if (sourceType.getEnclosingType() == null) { + type = new TypeDeclaration(compilationResult); + } else { + type = new MemberTypeDeclaration(compilationResult); + } + type.name = sourceType.getName(); + int start, end; // only positions available + type.sourceStart = start = sourceType.getNameSourceStart(); + type.sourceEnd = end = sourceType.getNameSourceEnd(); + type.modifiers = sourceType.getModifiers(); + type.declarationSourceStart = sourceType.getDeclarationSourceStart(); + type.declarationSourceEnd = sourceType.getDeclarationSourceEnd(); + type.bodyEnd = type.declarationSourceEnd; + + /* set superclass and superinterfaces */ + if (sourceType.getSuperclassName() != null) + type.superclass = + createTypeReference(sourceType.getSuperclassName(), start, end); + char[][] interfaceNames = sourceType.getInterfaceNames(); + int interfaceCount = interfaceNames == null ? 0 : interfaceNames.length; + type.superInterfaces = new TypeReference[interfaceCount]; + for (int i = 0; i < interfaceCount; i++) { + type.superInterfaces[i] = createTypeReference(interfaceNames[i], start, end); + } + /* convert member types */ + if (needMemberTypes) { + ISourceType[] sourceMemberTypes = sourceType.getMemberTypes(); + int sourceMemberTypeCount = + sourceMemberTypes == null ? 0 : sourceMemberTypes.length; + type.memberTypes = new MemberTypeDeclaration[sourceMemberTypeCount]; + for (int i = 0; i < sourceMemberTypeCount; i++) { + type.memberTypes[i] = + (MemberTypeDeclaration) convert(sourceMemberTypes[i], + needFieldsAndMethods, + true, + compilationResult); + } + } + /* convert fields and methods */ + if (needFieldsAndMethods) { + /* convert fields */ + ISourceField[] sourceFields = sourceType.getFields(); + int sourceFieldCount = sourceFields == null ? 0 : sourceFields.length; + type.fields = new FieldDeclaration[sourceFieldCount]; + for (int i = 0; i < sourceFieldCount; i++) { + type.fields[i] = convert(sourceFields[i]); + } + + /* convert methods - need to add default constructor if necessary */ + ISourceMethod[] sourceMethods = sourceType.getMethods(); + int sourceMethodCount = sourceMethods == null ? 0 : sourceMethods.length; + + /* source type has a constructor ? */ + /* by default, we assume that one is needed. */ + int neededCount = 1; + for (int i = 0; i < sourceMethodCount; i++) { + if (sourceMethods[i].isConstructor()) { + neededCount = 0; + // Does not need the extra constructor since one constructor already exists. + break; + } + } + type.methods = new AbstractMethodDeclaration[sourceMethodCount + neededCount]; + if (neededCount != 0) { // add default constructor in first position + type.methods[0] = type.createsInternalConstructor(false, false); + } + boolean isInterface = type.isInterface(); + for (int i = 0; i < sourceMethodCount; i++) { + AbstractMethodDeclaration method =convert(sourceMethods[i], compilationResult); + if (isInterface || method.isAbstract()) { // fix-up flag + method.modifiers |= AccSemicolonBody; + } + type.methods[neededCount + i] = method; + } + } + return type; + } + + /* + * Build an import reference from an import name, e.g. java.lang.* + */ + private static ImportReference createImportReference( + char[] importName, + int start, + int end) { + + /* count identifiers */ + int max = importName.length; + int identCount = 0; + for (int i = 0; i < max; i++) { + if (importName[i] == '.') + identCount++; + } + /* import on demand? */ + boolean onDemand = importName[max - 1] == '*'; + if (!onDemand) + identCount++; // one more ident than dots + + long[] positions = new long[identCount]; + long position = (long) start << 32 + end; + for (int i = 0; i < identCount; i++) { + positions[i] = position; + } + return new ImportReference( + CharOperation.splitOn('.', importName, 0, max - (onDemand ? 3 : 1)), + positions, + onDemand); + } + + /* + * Build a type reference from a readable name, e.g. java.lang.Object[][] + */ + private static TypeReference createTypeReference( + char[] typeSignature, + int start, + int end) { + + /* count identifiers and dimensions */ + int max = typeSignature.length; + int dimStart = max; + int dim = 0; + int identCount = 1; + for (int i = 0; i < max; i++) { + switch (typeSignature[i]) { + case '[' : + if (dim == 0) + dimStart = i; + dim++; + break; + case '.' : + identCount++; + break; + } + } + /* rebuild identifiers and dimensions */ + if (identCount == 1) { // simple type reference + if (dim == 0) { + return new SingleTypeReference(typeSignature, (((long) start )<< 32) + end); + } else { + char[] identifier = new char[dimStart]; + System.arraycopy(typeSignature, 0, identifier, 0, dimStart); + return new ArrayTypeReference(identifier, dim, (((long) start) << 32) + end); + } + } else { // qualified type reference + long[] positions = new long[identCount]; + long pos = (((long) start) << 32) + end; + for (int i = 0; i < identCount; i++) { + positions[i] = pos; + } + char[][] identifiers = + CharOperation.splitOn('.', typeSignature, 0, dimStart - 1); + if (dim == 0) { + return new QualifiedTypeReference(identifiers, positions); + } else { + return new ArrayQualifiedTypeReference(identifiers, dim, positions); + } + } + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/AbortCompilation.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/AbortCompilation.java new file mode 100644 index 0000000..bf960d0 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/AbortCompilation.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.problem; + +import net.sourceforge.phpdt.internal.compiler.CompilationResult; + +/* + * Special unchecked exception type used + * to abort from the compilation process + * + * should only be thrown from within problem handlers. + */ +public class AbortCompilation extends RuntimeException { + public CompilationResult compilationResult; + public Throwable exception; + + public int problemId; + public String[] problemArguments; + + /* special fields used to abort silently (e.g. when cancelling build process) */ + public boolean isSilent; + public RuntimeException silentException; +public AbortCompilation() { + this((CompilationResult)null); +} +public AbortCompilation(int problemId, String[] problemArguments) { + + this.problemId = problemId; + this.problemArguments = problemArguments; +} +public AbortCompilation(CompilationResult compilationResult) { + this(compilationResult, null); +} +public AbortCompilation(CompilationResult compilationResult, Throwable exception) { + this.compilationResult = compilationResult; + this.exception = exception; +} +public AbortCompilation(boolean isSilent, RuntimeException silentException) { + this.isSilent = isSilent; + this.silentException = silentException; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/AbortCompilationUnit.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/AbortCompilationUnit.java new file mode 100644 index 0000000..7d4b82c --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/AbortCompilationUnit.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.problem; + +import net.sourceforge.phpdt.internal.compiler.CompilationResult; + +/* + * Special unchecked exception type used + * to abort from the compilation process + * + * should only be thrown from within problem handlers. + */ +public class AbortCompilationUnit extends AbortCompilation { +public AbortCompilationUnit(CompilationResult compilationResult) { + super(compilationResult); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/AbortMethod.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/AbortMethod.java new file mode 100644 index 0000000..6c28f9a --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/AbortMethod.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.problem; + +import net.sourceforge.phpdt.internal.compiler.CompilationResult; + +/* + * Special unchecked exception type used + * to abort from the compilation process + * + * should only be thrown from within problem handlers. + */ +public class AbortMethod extends AbortType { +public AbortMethod(CompilationResult compilationResult) { + super(compilationResult); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/AbortType.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/AbortType.java new file mode 100644 index 0000000..b8b4540 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/AbortType.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.problem; + +import net.sourceforge.phpdt.internal.compiler.CompilationResult; + +/* + * Special unchecked exception type used + * to abort from the compilation process + * + * should only be thrown from within problem handlers. + */ +public class AbortType extends AbortCompilationUnit { +public AbortType(CompilationResult compilationResult) { + super(compilationResult); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/DefaultProblem.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/DefaultProblem.java new file mode 100644 index 0000000..9e433d3 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/DefaultProblem.java @@ -0,0 +1,249 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.problem; + +import net.sourceforge.phpdt.core.compiler.IProblem; +import net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit; +import net.sourceforge.phpdt.internal.compiler.util.Util; + +public class DefaultProblem implements ProblemSeverities, IProblem { + + private char[] fileName; + private int id; + private int startPosition, endPosition, line; + private int severity; + private String[] arguments; + private String message; + + public DefaultProblem( + char[] originatingFileName, + String message, + int id, + String[] stringArguments, + int severity, + int startPosition, + int endPosition, + int line) { + + this.fileName = originatingFileName; + this.message = message; + this.id = id; + this.arguments = stringArguments; + this.severity = severity; + this.startPosition = startPosition; + this.endPosition = endPosition; + this.line = line; + } + + public String errorReportSource(ICompilationUnit compilationUnit) { + //extra from the source the innacurate token + //and "highlight" it using some underneath ^^^^^ + //put some context around too. + + //this code assumes that the font used in the console is fixed size + + //sanity ..... + if ((startPosition > endPosition) + || ((startPosition <= 0) && (endPosition <= 0))) + return Util.bind("problem.noSourceInformation"); //$NON-NLS-1$ + + final char SPACE = '\u0020'; + final char MARK = '^'; + final char TAB = '\t'; + char[] source = compilationUnit.getContents(); + //the next code tries to underline the token..... + //it assumes (for a good display) that token source does not + //contain any \r \n. This is false on statements ! + //(the code still works but the display is not optimal !) + + //compute the how-much-char we are displaying around the inaccurate token + int begin = startPosition >= source.length ? source.length - 1 : startPosition; + int relativeStart = 0; + int end = endPosition >= source.length ? source.length - 1 : endPosition; + int relativeEnd = 0; + label : for (relativeStart = 0;; relativeStart++) { + if (begin == 0) + break label; + if ((source[begin - 1] == '\n') || (source[begin - 1] == '\r')) + break label; + begin--; + } + label : for (relativeEnd = 0;; relativeEnd++) { + if ((end + 1) >= source.length) + break label; + if ((source[end + 1] == '\r') || (source[end + 1] == '\n')) { + break label; + } + end++; + } + //extract the message form the source + char[] extract = new char[end - begin + 1]; + System.arraycopy(source, begin, extract, 0, extract.length); + char c; + //remove all SPACE and TAB that begin the error message... + int trimLeftIndex = 0; + while (((c = extract[trimLeftIndex++]) == TAB) || (c == SPACE)) { + }; + System.arraycopy( + extract, + trimLeftIndex - 1, + extract = new char[extract.length - trimLeftIndex + 1], + 0, + extract.length); + relativeStart -= trimLeftIndex; + //buffer spaces and tabs in order to reach the error position + int pos = 0; + char[] underneath = new char[extract.length]; // can't be bigger + for (int i = 0; i <= relativeStart; i++) { + if (extract[i] == TAB) { + underneath[pos++] = TAB; + } else { + underneath[pos++] = SPACE; + } + } + //mark the error position + for (int i = startPosition; + i <= (endPosition >= source.length ? source.length - 1 : endPosition); + i++) + underneath[pos++] = MARK; + //resize underneathto remove 'null' chars + System.arraycopy(underneath, 0, underneath = new char[pos], 0, pos); + + return " " + Util.bind("problem.atLine", String.valueOf(line)) //$NON-NLS-2$ //$NON-NLS-1$ + + "\n\t" + new String(extract) + "\n\t" + new String(underneath); //$NON-NLS-2$ //$NON-NLS-1$ + } + + /** + * Answer back the original arguments recorded into the problem. + * @return java.lang.String[] + */ + public String[] getArguments() { + + return arguments; + } + + /** + * Answer the type of problem. + * @see org.eclipse.jdt.core.compiler.IProblem#getID() + * @return int + */ + public int getID() { + + return id; + } + + /** + * Answer a localized, human-readable message string which describes the problem. + * @return java.lang.String + */ + public String getMessage() { + + return message; + } + + /** + * Answer the file name in which the problem was found. + * @return char[] + */ + public char[] getOriginatingFileName() { + + return fileName; + } + + /** + * Answer the end position of the problem (inclusive), or -1 if unknown. + * @return int + */ + public int getSourceEnd() { + + return endPosition; + } + + /** + * Answer the line number in source where the problem begins. + * @return int + */ + public int getSourceLineNumber() { + + return line; + } + + /** + * Answer the start position of the problem (inclusive), or -1 if unknown. + * @return int + */ + public int getSourceStart() { + + return startPosition; + } + + /* + * Helper method: checks the severity to see if the Error bit is set. + * @return boolean + */ + public boolean isError() { + + return (severity & ProblemSeverities.Error) != 0; + } + + /* + * Helper method: checks the severity to see if the Error bit is not set. + * @return boolean + */ + public boolean isWarning() { + + return (severity & ProblemSeverities.Error) == 0; + } + + /** + * Set the end position of the problem (inclusive), or -1 if unknown. + * + * Used for shifting problem positions. + * @param sourceEnd the new value of the sourceEnd of the receiver + */ + public void setSourceEnd(int sourceEnd) { + + endPosition = sourceEnd; + } + + /** + * Set the line number in source where the problem begins. + * @param lineNumber the new value of the line number of the receiver + */ + public void setSourceLineNumber(int lineNumber) { + + line = lineNumber; + } + + /** + * Set the start position of the problem (inclusive), or -1 if unknown. + * + * Used for shifting problem positions. + * @param sourceStart the new value of the source start position of the receiver + */ + public void setSourceStart(int sourceStart) { + + startPosition = sourceStart; + } + + public String toString() { + + String s = "Pb(" + (id & IgnoreCategoriesMask) + ") "; //$NON-NLS-1$ //$NON-NLS-2$ + if (message != null) { + s += message; + } else { + if (arguments != null) + for (int i = 0; i < arguments.length; i++) + s += " " + arguments[i]; //$NON-NLS-1$ + } + return s; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/DefaultProblemFactory.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/DefaultProblemFactory.java new file mode 100644 index 0000000..8809e15 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/DefaultProblemFactory.java @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.problem; + +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import net.sourceforge.phpdt.core.compiler.IProblem; +import net.sourceforge.phpdt.internal.compiler.IProblemFactory; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class DefaultProblemFactory implements IProblemFactory { + + + public String[] messageTemplates; + private Locale locale; + private static String[] DEFAULT_LOCALE_TEMPLATES; + private final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$ + private final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$ + +/** + * @param loc the locale used to get the right message + */ +public DefaultProblemFactory(Locale loc) { + this.locale = loc; + if (Locale.getDefault().equals(loc)){ + if (DEFAULT_LOCALE_TEMPLATES == null){ + DEFAULT_LOCALE_TEMPLATES = loadMessageTemplates(loc); + } + this.messageTemplates = DEFAULT_LOCALE_TEMPLATES; + } else { + this.messageTemplates = loadMessageTemplates(loc); + } +} +/** + * Answer a new IProblem created according to the parameters value + *
    + *
  • originatingFileName the name of the file name from which the problem is originated + *
  • problemId the problem id + *
  • arguments the arguments needed to set the error message + *
  • severity the severity of the problem + *
  • startPosition the starting position of the problem + *
  • endPosition the end position of the problem + *
  • lineNumber the line on which the problem occured + *
+ * @param originatingFileName char[] + * @param problemId int + * @param arguments String[] + * @param severity int + * @param startPosition int + * @param endPosition int + * @param lineNumber int + * @return org.eclipse.jdt.internal.compiler.IProblem + */ +public IProblem createProblem( + char[] originatingFileName, + int problemId, + String[] arguments, + int severity, + int startPosition, + int endPosition, + int lineNumber) { + + return new DefaultProblem( + originatingFileName, + this.getLocalizedMessage(problemId, arguments), + problemId, + arguments, + severity, + startPosition, + endPosition, + lineNumber); +} +/** + * Answer the locale used to retrieve the error messages + * @return java.util.Locale + */ +public Locale getLocale() { + return locale; +} +public final String getLocalizedMessage(int id, String[] problemArguments) { + StringBuffer output = new StringBuffer(80); + String message = + messageTemplates[(id & IProblem.IgnoreCategoriesMask)]; + if (message == null) { + return "Unable to retrieve the error message for problem id: " //$NON-NLS-1$ + + id + + ". Check compiler resources."; //$NON-NLS-1$ + } + + // for compatibility with MessageFormat which eliminates double quotes in original message + char[] messageWithNoDoubleQuotes = + CharOperation.replace(message.toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE); + message = new String(messageWithNoDoubleQuotes); + + int length = message.length(); + int start = -1, end = length; + while (true) { + if ((end = message.indexOf('{', start)) > -1) { + output.append(message.substring(start + 1, end)); + if ((start = message.indexOf('}', end)) > -1) { + try { + output.append( + problemArguments[Integer.parseInt(message.substring(end + 1, start))]); + } catch (NumberFormatException nfe) { + output.append(message.substring(end + 1, start + 1)); + } catch (ArrayIndexOutOfBoundsException e) { + return "Corrupted compiler resources for problem id: " //$NON-NLS-1$ + + (id & IProblem.IgnoreCategoriesMask) + + ". Check compiler resources."; //$NON-NLS-1$ + } + } else { + output.append(message.substring(end, length)); + break; + } + } else { + output.append(message.substring(start + 1, length)); + break; + } + } + return output.toString(); +} +/** + * @param problem org.eclipse.jdt.internal.compiler.IProblem + * @return String + */ +public final String localizedMessage(IProblem problem) { + return getLocalizedMessage(problem.getID(), problem.getArguments()); +} + +/** + * This method initializes the MessageTemplates class variable according + * to the current Locale. + */ +public static String[] loadMessageTemplates(Locale loc) { + ResourceBundle bundle = ResourceBundle.getBundle("org.eclipse.jdt.internal.compiler.problem.messages", loc); //$NON-NLS-1$ + String[] templates = new String[500]; + for (int i = 0, max = templates.length; i < max; i++) { + try { + templates[i] = bundle.getString(String.valueOf(i)); + } catch (MissingResourceException e) { + // available ID + } + } + return templates; +} + +public DefaultProblemFactory() { + this(Locale.getDefault()); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/ProblemHandler.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/ProblemHandler.java new file mode 100644 index 0000000..9295af1 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/ProblemHandler.java @@ -0,0 +1,180 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.problem; + +import net.sourceforge.phpdt.core.compiler.IProblem; +import net.sourceforge.phpdt.internal.compiler.CompilationResult; +import net.sourceforge.phpdt.internal.compiler.IErrorHandlingPolicy; +import net.sourceforge.phpdt.internal.compiler.IProblemFactory; +import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions; +import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext; + +/* + * Compiler error handler, responsible to determine whether + * a problem is actually a warning or an error; also will + * decide whether the compilation task can be processed further or not. + * + * Behavior : will request its current policy if need to stop on + * first error, and if should proceed (persist) with problems. + */ + +public class ProblemHandler implements ProblemSeverities { + + final public IErrorHandlingPolicy policy; + public final IProblemFactory problemFactory; + public final CompilerOptions options; +/* + * Problem handler can be supplied with a policy to specify + * its behavior in error handling. Also see static methods for + * built-in policies. + * + */ +public ProblemHandler(IErrorHandlingPolicy policy, CompilerOptions options, IProblemFactory problemFactory) { + this.policy = policy; + this.problemFactory = problemFactory; + this.options = options; +} +/* + * Given the current configuration, answers which category the problem + * falls into: + * Error | Warning | Ignore + */ +public int computeSeverity(int problemId){ + + return Error; // by default all problems are errors +} +public IProblem createProblem( + char[] fileName, + int problemId, + String[] problemArguments, + int severity, + int problemStartPosition, + int problemEndPosition, + int lineNumber, + ReferenceContext referenceContext, + CompilationResult unitResult) { + + return problemFactory.createProblem( + fileName, + problemId, + problemArguments, + severity, + problemStartPosition, + problemEndPosition, + lineNumber); +} +public void handle( + int problemId, + String[] problemArguments, + int severity, + int problemStartPosition, + int problemEndPosition, + ReferenceContext referenceContext, + CompilationResult unitResult) { + + if (severity == Ignore) + return; + + // if no reference context, we need to abort from the current compilation process + if (referenceContext == null) { + if ((severity & Error) != 0) { // non reportable error is fatal + throw new AbortCompilation(problemId, problemArguments); + } else { + return; // ignore non reportable warning + } + } + + IProblem problem = + this.createProblem( + unitResult.getFileName(), + problemId, + problemArguments, + severity, + problemStartPosition, + problemEndPosition, + problemStartPosition >= 0 + ? searchLineNumber(unitResult.lineSeparatorPositions, problemStartPosition) + : 0, + referenceContext, + unitResult); + if (problem == null) return; // problem couldn't be created, ignore + + switch (severity & Error) { + case Error : + this.record(problem, unitResult, referenceContext); + referenceContext.tagAsHavingErrors(); + + // should abort ? + int abortLevel; + if ((abortLevel = + (policy.stopOnFirstError() ? AbortCompilation : severity & Abort)) != 0) { + + referenceContext.abort(abortLevel); + } + break; + case Warning : + this.record(problem, unitResult, referenceContext); + break; + } +} +/** + * Standard problem handling API, the actual severity (warning/error/ignore) is deducted + * from the problem ID and the current compiler options. + */ +public void handle( + int problemId, + String[] problemArguments, + int problemStartPosition, + int problemEndPosition, + ReferenceContext referenceContext, + CompilationResult unitResult) { + + this.handle( + problemId, + problemArguments, + this.computeSeverity(problemId), // severity inferred using the ID + problemStartPosition, + problemEndPosition, + referenceContext, + unitResult); +} +public void record(IProblem problem, CompilationResult unitResult, ReferenceContext referenceContext) { + unitResult.record(problem, referenceContext); +} +/** + * Search the line number corresponding to a specific position + * + * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding + */ +public static final int searchLineNumber(int[] startLineIndexes, int position) { + 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; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/ProblemReporter.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/ProblemReporter.java new file mode 100644 index 0000000..1d4f0bf --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/ProblemReporter.java @@ -0,0 +1,2501 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.problem; + +import net.sourceforge.phpdt.core.compiler.IProblem; +import net.sourceforge.phpdt.core.compiler.ITerminalSymbols; +import net.sourceforge.phpdt.core.compiler.InvalidInputException; +import net.sourceforge.phpdt.internal.compiler.*; +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.parser.*; +import net.sourceforge.phpdt.internal.compiler.util.*; +import net.sourceforge.phpdt.internal.compiler.impl.*; + +public class ProblemReporter extends ProblemHandler implements ProblemReasons { + + public ReferenceContext referenceContext; +public ProblemReporter(IErrorHandlingPolicy policy, CompilerOptions options, IProblemFactory problemFactory) { + super(policy, options, problemFactory); +} +public void abortDueToInternalError(String errorMessage) { + this.handle( + IProblem.Unclassified, + new String[] {errorMessage}, + Error | Abort, + 0, + 0); +} +public void abortDueToInternalError(String errorMessage, AstNode location) { + this.handle( + IProblem.Unclassified, + new String[] {errorMessage}, + Error | Abort, + location.sourceStart, + location.sourceEnd); +} +public void abstractMethodCannotBeOverridden(SourceTypeBinding type, MethodBinding concreteMethod) { + + this.handle( + // %1 must be abstract since it cannot override the inherited package-private abstract method %2 + IProblem.AbstractMethodCannotBeOverridden, + new String[] {new String(type.sourceName()), new String(concreteMethod.readableName())}, + type.sourceStart(), + type.sourceEnd()); +} +public void abstractMethodInAbstractClass(SourceTypeBinding type, AbstractMethodDeclaration methodDecl) { + this.handle( + IProblem.AbstractMethodInAbstractClass, + new String[] {new String(type.sourceName()), new String(methodDecl.selector)}, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void abstractMethodMustBeImplemented(SourceTypeBinding type, MethodBinding abstractMethod) { + this.handle( + // Must implement the inherited abstract method %1 + // 8.4.3 - Every non-abstract subclass of an abstract type, A, must provide a concrete implementation of all of A's methods. + IProblem.AbstractMethodMustBeImplemented, + new String[] { + new String( + CharOperation.concat( + abstractMethod.declaringClass.readableName(), + abstractMethod.readableName(), + '.'))}, + type.sourceStart(), + type.sourceEnd()); +} +public void abstractMethodNeedingNoBody(AbstractMethodDeclaration method) { + this.handle( + IProblem.BodyForAbstractMethod, + new String[0], + method.sourceStart, + method.sourceEnd, + method, + method.compilationResult()); +} +public void alreadyDefinedLabel(char[] labelName, AstNode location) { + this.handle( + IProblem.DuplicateLabel, + new String[] {new String(labelName)}, + location.sourceStart, + location.sourceEnd); +} +public void anonymousClassCannotExtendFinalClass(Expression expression, TypeBinding type) { + this.handle( + IProblem.AnonymousClassCannotExtendFinalClass, + new String[] {new String(type.readableName())}, + expression.sourceStart, + expression.sourceEnd); +} +public void argumentTypeCannotBeVoid(SourceTypeBinding type, AbstractMethodDeclaration methodDecl, Argument arg) { + this.handle( + IProblem.ArgumentTypeCannotBeVoid, + new String[] {new String(methodDecl.selector), new String(arg.name)}, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void argumentTypeCannotBeVoidArray(SourceTypeBinding type, AbstractMethodDeclaration methodDecl, Argument arg) { + this.handle( + IProblem.ArgumentTypeCannotBeVoidArray, + new String[] {new String(methodDecl.selector), new String(arg.name)}, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void argumentTypeProblem(SourceTypeBinding type, AbstractMethodDeclaration methodDecl, Argument arg, TypeBinding expectedType) { + int problemId = expectedType.problemId(); + int id; + switch (problemId) { + case NotFound : // 1 + id = IProblem.ArgumentTypeNotFound; + break; + case NotVisible : // 2 + id = IProblem.ArgumentTypeNotVisible; + break; + case Ambiguous : // 3 + id = IProblem.ArgumentTypeAmbiguous; + break; + case InternalNameProvided : // 4 + id = IProblem.ArgumentTypeInternalNameProvided; + break; + case InheritedNameHidesEnclosingName : // 5 + id = IProblem.ArgumentTypeInheritedNameHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + return; + } + this.handle( + id, + new String[] {new String(methodDecl.selector), arg.name(), new String(expectedType.readableName())}, + arg.type.sourceStart, + arg.type.sourceEnd); +} +public void arrayConstantsOnlyInArrayInitializers(int sourceStart, int sourceEnd) { + this.handle( + IProblem.ArrayConstantsOnlyInArrayInitializers, + new String[0], + sourceStart, + sourceEnd); +} +public void attemptToReturnNonVoidExpression(ReturnStatement returnStatement, TypeBinding expectedType) { + this.handle( + IProblem.VoidMethodReturnsValue, + new String[] {new String(expectedType.readableName())}, + returnStatement.sourceStart, + returnStatement.sourceEnd); +} +public void attemptToReturnVoidValue(ReturnStatement returnStatement) { + this.handle( + IProblem.MethodReturnsVoid, + new String[] {}, + returnStatement.sourceStart, + returnStatement.sourceEnd); +} +public void bytecodeExceeds64KLimit(AbstractMethodDeclaration location) { + this.handle( + IProblem.BytecodeExceeds64KLimit, + new String[] {new String(location.selector)}, + Error | Abort, + location.sourceStart, + location.sourceEnd); +} +public void bytecodeExceeds64KLimit(TypeDeclaration location) { + this.handle( + IProblem.BytecodeExceeds64KLimitForClinit, + new String[0], + Error | Abort, + location.sourceStart, + location.sourceEnd); +} +public void cannotAllocateVoidArray(Expression expression) { + this.handle( + IProblem.CannotAllocateVoidArray, + new String[] {}, + expression.sourceStart, + expression.sourceEnd); +} +public void cannotAssignToFinalField(FieldBinding field, AstNode location) { + this.handle( + IProblem.FinalFieldAssignment, + new String[] { + (field.declaringClass == null ? "array" : new String(field.declaringClass.readableName())), //$NON-NLS-1$ + new String(field.readableName())}, + location.sourceStart, + location.sourceEnd); +} +public void cannotAssignToFinalOuterLocal(LocalVariableBinding local, AstNode location) { + this.handle( + IProblem.FinalOuterLocalAssignment, + new String[] {new String(local.readableName())}, + location.sourceStart, + location.sourceEnd); +} +public void cannotDeclareLocalInterface(char[] interfaceName, int sourceStart, int sourceEnd) { + this.handle( + IProblem.CannotDefineInterfaceInLocalType, + new String[] {new String(interfaceName)}, + sourceStart, + sourceEnd); +} +public void cannotDefineDimensionsAndInitializer(ArrayAllocationExpression expresssion) { + this.handle( + IProblem.CannotDefineDimensionExpressionsWithInit, + new String[0], + expresssion.sourceStart, + expresssion.sourceEnd); +} +public void cannotDireclyInvokeAbstractMethod(MessageSend messageSend, MethodBinding method) { + this.handle( + IProblem.DirectInvocationOfAbstractMethod, + new String[] {new String(method.declaringClass.readableName()), new String(method.selector), parametersAsString(method)}, + messageSend.sourceStart, + messageSend.sourceEnd); +} +public void cannotImportPackage(ImportReference importRef) { + this.handle( + IProblem.CannotImportPackage, + new String[] {CharOperation.toString(importRef.tokens)}, + importRef.sourceStart, + importRef.sourceEnd); +} +public void cannotInstantiate(TypeReference typeRef, TypeBinding type) { + this.handle( + IProblem.InvalidClassInstantiation, + new String[] {new String(type.readableName())}, + typeRef.sourceStart, + typeRef.sourceEnd); +} +public void cannotReferToNonFinalOuterLocal(LocalVariableBinding local, AstNode location) { + this.handle( + IProblem.OuterLocalMustBeFinal, + new String[] {new String(local.readableName())}, + location.sourceStart, + location.sourceEnd); +} +public void cannotReturnInInitializer(AstNode location) { + this.handle( + IProblem.CannotReturnInInitializer, + new String[0], + location.sourceStart, + location.sourceEnd); +} +public void cannotThrowNull(ThrowStatement statement) { + this.handle( + IProblem.CannotThrowNull, + new String[0], + statement.sourceStart, + statement.sourceEnd); +} +public void cannotThrowType(SourceTypeBinding type, AbstractMethodDeclaration methodDecl, TypeReference exceptionType, TypeBinding expectedType) { + this.handle( + IProblem.CannotThrowType, + new String[] {new String(expectedType.readableName())}, + exceptionType.sourceStart, + exceptionType.sourceEnd); +} +public void cannotUseSuperInJavaLangObject(AstNode reference) { + this.handle( + IProblem.ObjectHasNoSuperclass, + new String[0], + reference.sourceStart, + reference.sourceEnd); +} +public void cannotUseSuperInCodeSnippet(int start, int end) { + this.handle( + IProblem.CannotUseSuperInCodeSnippet, + new String[0], + Error | Abort, + start, + end); +} +public void caseExpressionMustBeConstant(Expression expression) { + this.handle( + IProblem.NonConstantExpression, + new String[0], + expression.sourceStart, + expression.sourceEnd); +} +public void classExtendFinalClass(SourceTypeBinding type, TypeReference superclass, TypeBinding expectedType) { + this.handle( + IProblem.ClassExtendFinalClass, + new String[] {new String(expectedType.readableName()), new String(type.sourceName())}, + superclass.sourceStart, + superclass.sourceEnd); +} +public void codeSnippetMissingClass(String missing, int start, int end) { + this.handle( + IProblem.CodeSnippetMissingClass, + new String[]{ missing }, + Error | Abort, + start, + end); +} +public void codeSnippetMissingMethod(String className, String missingMethod, String argumentTypes, int start, int end) { + this.handle( + IProblem.CodeSnippetMissingMethod, + new String[]{ className, missingMethod, argumentTypes }, + Error | Abort, + start, + end); +} +/* + * Given the current configuration, answers which category the problem + * falls into: + * Error | Warning | Ignore + */ +public int computeSeverity(int problemId){ + + // severity can have been preset on the problem +// if ((problem.severity & Fatal) != 0){ +// return Error; +// } + + // if not then check whether it is a configurable problem + int errorThreshold = options.errorThreshold; + int warningThreshold = options.warningThreshold; + + switch(problemId){ + + case IProblem.UnreachableCatch : + case IProblem.CodeCannotBeReached : + if ((errorThreshold & CompilerOptions.UnreachableCode) != 0){ + return Error; + } + if ((warningThreshold & CompilerOptions.UnreachableCode) != 0){ + return Warning; + } + return Ignore; + + case IProblem.MaskedCatch : + if ((errorThreshold & CompilerOptions.MaskedCatchBlock) != 0){ + return Error; + } + if ((warningThreshold & CompilerOptions.MaskedCatchBlock) != 0){ + return Warning; + } + return Ignore; + +/* + case Never Used : + if ((errorThreshold & ParsingOptionalError) != 0){ + return Error; + } + if ((warningThreshold & ParsingOptionalError) != 0){ + return Warning; + } + return Ignore; +*/ + case IProblem.ImportNotFound : + case IProblem.ImportNotVisible : + case IProblem.ImportAmbiguous : + case IProblem.ImportInternalNameProvided : + case IProblem.ImportInheritedNameHidesEnclosingName : + case IProblem.DuplicateImport : + case IProblem.ConflictingImport : + case IProblem.CannotImportPackage : + if ((errorThreshold & CompilerOptions.ImportProblem) != 0){ + return Error; + } + if ((warningThreshold & CompilerOptions.ImportProblem) != 0){ + return Warning; + } + return Ignore; + + case IProblem.UnusedImport : + // if import problem are disabled, then ignore + if ((errorThreshold & CompilerOptions.ImportProblem) == 0 + && (warningThreshold & CompilerOptions.ImportProblem) == 0){ + return Ignore; + } + if ((errorThreshold & CompilerOptions.UnusedImport) != 0){ + return Error; + } + if ((warningThreshold & CompilerOptions.UnusedImport) != 0){ + return Warning; + } + return Ignore; + +/* + case UnnecessaryEnclosingInstanceSpecification : + if ((errorThreshold & UnnecessaryEnclosingInstance) != 0){ + return Error; + } + if ((warningThreshold & UnnecessaryEnclosingInstance) != 0){ + return Warning; + } + return Ignore; +*/ + case IProblem.MethodButWithConstructorName : + if ((errorThreshold & CompilerOptions.MethodWithConstructorName) != 0){ + return Error; + } + if ((warningThreshold & CompilerOptions.MethodWithConstructorName) != 0){ + return Warning; + } + return Ignore; + + case IProblem.OverridingNonVisibleMethod : + if ((errorThreshold & CompilerOptions.OverriddenPackageDefaultMethod) != 0){ + return Error; + } + if ((warningThreshold & CompilerOptions.OverriddenPackageDefaultMethod) != 0){ + return Warning; + } + return Ignore; + + case IProblem.OverridingDeprecatedMethod : + case IProblem.UsingDeprecatedType : + case IProblem.UsingDeprecatedMethod : + case IProblem.UsingDeprecatedConstructor : + case IProblem.UsingDeprecatedField : + if ((errorThreshold & CompilerOptions.UsingDeprecatedAPI) != 0){ + return Error; + } + if ((warningThreshold & CompilerOptions.UsingDeprecatedAPI) != 0){ + return Warning; + } + return Ignore; + + case IProblem.LocalVariableIsNeverUsed : + if ((errorThreshold & CompilerOptions.UnusedLocalVariable) != 0){ + return Error; + } + if ((warningThreshold & CompilerOptions.UnusedLocalVariable) != 0){ + return Warning; + } + return Ignore; + + case IProblem.ArgumentIsNeverUsed : + if ((errorThreshold & CompilerOptions.UnusedArgument) != 0){ + return Error; + } + if ((warningThreshold & CompilerOptions.UnusedArgument) != 0){ + return Warning; + } + return Ignore; + + case IProblem.NoImplicitStringConversionForCharArrayExpression : + if ((errorThreshold & CompilerOptions.NoImplicitStringConversion) != 0){ + return Error; + } + if ((warningThreshold & CompilerOptions.NoImplicitStringConversion) != 0){ + return Warning; + } + return Ignore; + + case IProblem.NeedToEmulateFieldReadAccess : + case IProblem.NeedToEmulateFieldWriteAccess : + case IProblem.NeedToEmulateMethodAccess : + case IProblem.NeedToEmulateConstructorAccess : + if ((errorThreshold & CompilerOptions.AccessEmulation) != 0){ + return Error; + } + if ((warningThreshold & CompilerOptions.AccessEmulation) != 0){ + return Warning; + } + return Ignore; + case IProblem.NonExternalizedStringLiteral : + if ((errorThreshold & CompilerOptions.NonExternalizedString) != 0){ + return Error; + } + if ((warningThreshold & CompilerOptions.NonExternalizedString) != 0){ + return Warning; + } + return Ignore; + case IProblem.UseAssertAsAnIdentifier : + if ((errorThreshold & CompilerOptions.AssertUsedAsAnIdentifier) != 0){ + return Error; + } + if ((warningThreshold & CompilerOptions.AssertUsedAsAnIdentifier) != 0){ + return Warning; + } + return Ignore; + default: + return Error; + } +} +public void conditionalArgumentsIncompatibleTypes(ConditionalExpression expression, TypeBinding trueType, TypeBinding falseType) { + this.handle( + IProblem.IncompatibleTypesInConditionalOperator, + new String[] {new String(trueType.readableName()), new String(falseType.readableName())}, + expression.sourceStart, + expression.sourceEnd); +} +public void conflictingImport(ImportReference importRef) { + this.handle( + IProblem.ConflictingImport, + new String[] {CharOperation.toString(importRef.tokens)}, + importRef.sourceStart, + importRef.sourceEnd); +} +public void constantOutOfFormat(NumberLiteral lit) { + // the literal is not in a correct format + // this code is called on IntLiteral and LongLiteral + // example 000811 ...the 8 is uncorrect. + + if ((lit instanceof LongLiteral) || (lit instanceof IntLiteral)) { + char[] source = lit.source(); + try { + final String Radix; + final int radix; + if ((source[1] == 'x') || (source[1] == 'X')) { + radix = 16; + Radix = "Hexa"; //$NON-NLS-1$ + } else { + radix = 8; + Radix = "Octal"; //$NON-NLS-1$ + } + //look for the first digit that is incorrect + int place = -1; + label : for (int i = radix == 8 ? 1 : 2; i < source.length; i++) { + if (Character.digit(source[i], radix) == -1) { + place = i; + break label; + } + } + + this.handle( + IProblem.NumericValueOutOfRange, + new String[] {Radix + " " + new String(source) + " (digit " + new String(new char[] {source[place]}) + ")"}, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + lit.sourceStart, + lit.sourceEnd); + return; + } catch (IndexOutOfBoundsException ex) {} + + // just in case .... use a predefined error.. + // we should never come here...(except if the code changes !) + this.constantOutOfRange(lit); + } +} +public void constantOutOfRange(Literal lit) { + // lit is some how out of range of it declared type + // example 9999999999999999999999999999999999999999999999999999999999999999999 + + this.handle( + IProblem.NumericValueOutOfRange, + new String[] {new String(lit.source())}, + lit.sourceStart, + lit.sourceEnd); +} +public void deprecatedField(FieldBinding field, AstNode location) { + this.handle( + IProblem.UsingDeprecatedField, + new String[] {new String(field.declaringClass.readableName()), new String(field.name)}, + location.sourceStart, + location.sourceEnd); +} +public void deprecatedMethod(MethodBinding method, AstNode location) { + if (method.isConstructor()) + this.handle( + IProblem.UsingDeprecatedConstructor, + new String[] {new String(method.declaringClass.readableName()), parametersAsString(method)}, + location.sourceStart, + location.sourceEnd); + else + this.handle( + IProblem.UsingDeprecatedMethod, + new String[] {new String(method.declaringClass.readableName()), new String(method.selector), parametersAsString(method)}, + location.sourceStart, + location.sourceEnd); +} +public void deprecatedType(TypeBinding type, AstNode location) { + if (location == null) return; // 1G828DN - no type ref for synthetic arguments + this.handle( + IProblem.UsingDeprecatedType, + new String[] {new String(type.readableName())}, + location.sourceStart, + location.sourceEnd); +} +public void duplicateCase(Case statement, Constant constant) { + this.handle( + IProblem.DuplicateCase, + new String[] {String.valueOf(constant.intValue())}, + statement.sourceStart, + statement.sourceEnd); +} +public void duplicateDefaultCase(DefaultCase statement) { + this.handle( + IProblem.DuplicateDefaultCase, + new String[0], + statement.sourceStart, + statement.sourceEnd); +} +public void duplicateFieldInType(SourceTypeBinding type, FieldDeclaration fieldDecl) { + this.handle( + IProblem.DuplicateField, + new String[] {new String(type.sourceName()), fieldDecl.name()}, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); +} +public void duplicateImport(ImportReference importRef) { + this.handle( + IProblem.DuplicateImport, + new String[] {CharOperation.toString(importRef.tokens)}, + importRef.sourceStart, + importRef.sourceEnd); +} +public void duplicateInitializationOfBlankFinalField(FieldBinding field, Reference reference) { + this.handle( + IProblem.DuplicateBlankFinalFieldInitialization, + new String[] {new String(field.readableName())}, + reference.sourceStart, + reference.sourceEnd); +} +public void duplicateInitializationOfFinalLocal(LocalVariableBinding local, NameReference reference) { + this.handle( + IProblem.DuplicateFinalLocalInitialization, + new String[] {new String(local.readableName())}, + reference.sourceStart, + reference.sourceEnd); +} +public void duplicateMethodInType(SourceTypeBinding type, AbstractMethodDeclaration methodDecl) { + this.handle( + IProblem.DuplicateMethod, + new String[] {new String(methodDecl.selector), new String(type.sourceName())}, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void duplicateModifierForField(ReferenceBinding type, FieldDeclaration fieldDecl) { +/* to highlight modifiers use: + this.handle( + new Problem( + DuplicateModifierForField, + new String[] {fieldDecl.name()}, + fieldDecl.modifiers.sourceStart, + fieldDecl.modifiers.sourceEnd)); +*/ + + this.handle( + IProblem.DuplicateModifierForField, + new String[] {fieldDecl.name()}, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); +} +public void duplicateModifierForMethod(ReferenceBinding type, AbstractMethodDeclaration methodDecl) { + this.handle( + IProblem.DuplicateModifierForMethod, + new String[] {new String(type.sourceName()), new String(methodDecl.selector)}, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void duplicateModifierForType(SourceTypeBinding type) { + this.handle( + IProblem.DuplicateModifierForType, + new String[] {new String(type.sourceName())}, + type.sourceStart(), + type.sourceEnd()); +} +public void duplicateModifierForVariable(LocalDeclaration localDecl, boolean complainForArgument) { + this.handle( + complainForArgument + ? IProblem.DuplicateModifierForArgument + : IProblem.DuplicateModifierForVariable, + new String[] {localDecl.name()}, + localDecl.sourceStart, + localDecl.sourceEnd); +} +public void duplicateNestedType(TypeDeclaration typeDecl) { + this.handle( + IProblem.DuplicateNestedType, + new String[] {new String(typeDecl.name)}, + typeDecl.sourceStart, + typeDecl.sourceEnd); +} +public void duplicateSuperinterface(SourceTypeBinding type, TypeDeclaration typeDecl, ReferenceBinding superType) { + this.handle( + IProblem.DuplicateSuperInterface, + new String[] { + new String(superType.readableName()), + new String(type.sourceName())}, + typeDecl.sourceStart, + typeDecl.sourceEnd); +} +public void duplicateTypes(CompilationUnitDeclaration compUnitDecl, TypeDeclaration typeDecl) { + this.referenceContext = typeDecl; // report the problem against the type not the entire compilation unit + this.handle( + IProblem.DuplicateTypes, + new String[] {new String(compUnitDecl.getFileName()), new String(typeDecl.name)}, + typeDecl.sourceStart, + typeDecl.sourceEnd, + compUnitDecl.compilationResult); +} +public void errorNoMethodFor(MessageSend messageSend, TypeBinding recType, TypeBinding[] params) { + StringBuffer buffer = new StringBuffer(); + for (int i = 0, length = params.length; i < length; i++) { + if (i != 0) + buffer.append(", "); //$NON-NLS-1$ + buffer.append(new String(params[i].readableName())); + } + + this.handle( + recType.isArrayType() ? IProblem.NoMessageSendOnArrayType : IProblem.NoMessageSendOnBaseType, + new String[] {new String(recType.readableName()), new String(messageSend.selector), buffer.toString()}, + messageSend.sourceStart, + messageSend.sourceEnd); +} +public void errorThisSuperInStatic(AstNode reference) { + this.handle( + IProblem.ThisInStaticContext, + new String[] {reference.isSuper() ? "super" : "this"}, //$NON-NLS-2$ //$NON-NLS-1$ + reference.sourceStart, + reference.sourceEnd); +} +public void exceptionTypeProblem(SourceTypeBinding type, AbstractMethodDeclaration methodDecl, TypeReference exceptionType, TypeBinding expectedType) { + int problemId = expectedType.problemId(); + int id; + switch (problemId) { + case NotFound : // 1 + id = IProblem.ExceptionTypeNotFound; + break; + case NotVisible : // 2 + id = IProblem.ExceptionTypeNotVisible; + break; + case Ambiguous : // 3 + id = IProblem.ExceptionTypeAmbiguous; + break; + case InternalNameProvided : // 4 + id = IProblem.ExceptionTypeInternalNameProvided; + break; + case InheritedNameHidesEnclosingName : // 5 + id = IProblem.ExceptionTypeInheritedNameHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + return; + } + this.handle( + id, + new String[] {new String(methodDecl.selector), new String(expectedType.readableName())}, + exceptionType.sourceStart, + exceptionType.sourceEnd); +} +public void fieldsOrThisBeforeConstructorInvocation(ThisReference reference) { + this.handle( + IProblem.ThisSuperDuringConstructorInvocation, + new String[0], + reference.sourceStart, + reference.sourceEnd); +} +public void fieldTypeProblem(SourceTypeBinding type, FieldDeclaration fieldDecl, TypeBinding expectedType) { + int problemId = expectedType.problemId(); + int id; + switch (problemId) { + case NotFound : // 1 + id = IProblem.FieldTypeNotFound; + break; + case NotVisible : // 2 + id = IProblem.FieldTypeNotVisible; + break; + case Ambiguous : // 3 + id = IProblem.FieldTypeAmbiguous; + break; + case InternalNameProvided : // 4 + id = IProblem.FieldTypeInternalNameProvided; + break; + case InheritedNameHidesEnclosingName : // 5 + id = IProblem.FieldTypeInheritedNameHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + return; + } + this.handle( + id, + new String[] {fieldDecl.name(), new String(type.sourceName()), new String(expectedType.readableName())}, + fieldDecl.type.sourceStart, + fieldDecl.type.sourceEnd); +} +public void finalMethodCannotBeOverridden(MethodBinding currentMethod, MethodBinding inheritedMethod) { + this.handle( + // Cannot override the final method from %1 + // 8.4.3.3 - Final methods cannot be overridden or hidden. + IProblem.FinalMethodCannotBeOverridden, + new String[] {new String(inheritedMethod.declaringClass.readableName())}, + currentMethod.sourceStart(), + currentMethod.sourceEnd()); +} +public void forwardReference(Reference reference, int indexInQualification, TypeBinding type) { + this.handle( + IProblem.ReferenceToForwardField, + new String[] {}, + reference.sourceStart, + reference.sourceEnd); +} +// use this private API when the compilation unit result can be found through the +// reference context. Otherwise, use the other API taking a problem and a compilation result +// as arguments + +private void handle( + int problemId, + String[] problemArguments, + int problemStartPosition, + int problemEndPosition){ + + this.handle( + problemId, + problemArguments, + problemStartPosition, + problemEndPosition, + referenceContext, + referenceContext == null ? null : referenceContext.compilationResult()); + referenceContext = null; +} +// use this private API when the compilation unit result can be found through the +// reference context. Otherwise, use the other API taking a problem and a compilation result +// as arguments + +private void handle( + int problemId, + String[] problemArguments, + int severity, + int problemStartPosition, + int problemEndPosition){ + + this.handle( + problemId, + problemArguments, + severity, + problemStartPosition, + problemEndPosition, + referenceContext, + referenceContext == null ? null : referenceContext.compilationResult()); + referenceContext = null; +} +// use this private API when the compilation unit result cannot be found through the +// reference context. + +private void handle( + int problemId, + String[] problemArguments, + int problemStartPosition, + int problemEndPosition, + CompilationResult unitResult){ + + this.handle( + problemId, + problemArguments, + problemStartPosition, + problemEndPosition, + referenceContext, + unitResult); + referenceContext = null; +} +public void hidingEnclosingType(TypeDeclaration typeDecl) { + this.handle( + IProblem.HidingEnclosingType, + new String[] {new String(typeDecl.name)}, + typeDecl.sourceStart, + typeDecl.sourceEnd); +} +public void hierarchyCircularity(SourceTypeBinding sourceType, ReferenceBinding superType, TypeReference reference) { + int start = 0; + int end = 0; + String typeName = ""; //$NON-NLS-1$ + + if (reference == null) { // can only happen when java.lang.Object is busted + start = sourceType.sourceStart(); + end = sourceType.sourceEnd(); + typeName = new String(superType.readableName()); + } else { + start = reference.sourceStart; + end = reference.sourceEnd; + typeName = CharOperation.toString(reference.getTypeName()); + } + + if (sourceType == superType) + this.handle( + IProblem.HierarchyCircularitySelfReference, + new String[] {new String(sourceType.sourceName()), typeName}, + start, + end); + else + this.handle( + IProblem.HierarchyCircularity, + new String[] {new String(sourceType.sourceName()), typeName}, + start, + end); +} +public void hierarchyHasProblems(SourceTypeBinding type) { + this.handle( + IProblem.HierarchyHasProblems, + new String[] {new String(type.sourceName())}, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalAbstractModifierCombinationForMethod(ReferenceBinding type, AbstractMethodDeclaration methodDecl) { + this.handle( + IProblem.IllegalAbstractModifierCombinationForMethod, + new String[] {new String(type.sourceName()), new String(methodDecl.selector)}, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void illegalModifierCombinationFinalAbstractForClass(SourceTypeBinding type) { + this.handle( + IProblem.IllegalModifierCombinationFinalAbstractForClass, + new String[] {new String(type.sourceName())}, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalModifierCombinationFinalVolatileForField(ReferenceBinding type, FieldDeclaration fieldDecl) { + this.handle( + IProblem.IllegalModifierCombinationFinalVolatileForField, + new String[] {fieldDecl.name()}, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); +} + +public void illegalModifierForClass(SourceTypeBinding type) { + this.handle( + IProblem.IllegalModifierForClass, + new String[] {new String(type.sourceName())}, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalModifierForField(ReferenceBinding type, FieldDeclaration fieldDecl) { + this.handle( + IProblem.IllegalModifierForField, + new String[] {fieldDecl.name()}, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); +} +public void illegalModifierForInterface(SourceTypeBinding type) { + this.handle( + IProblem.IllegalModifierForInterface, + new String[] {new String(type.sourceName())}, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalModifierForInterfaceField(ReferenceBinding type, FieldDeclaration fieldDecl) { + this.handle( + IProblem.IllegalModifierForInterfaceField, + new String[] {fieldDecl.name()}, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); +} +public void illegalModifierForInterfaceMethod(ReferenceBinding type, AbstractMethodDeclaration methodDecl) { + this.handle( + IProblem.IllegalModifierForInterfaceMethod, + new String[] {new String(type.sourceName()), new String(methodDecl.selector)}, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void illegalModifierForLocalClass(SourceTypeBinding type) { + this.handle( + IProblem.IllegalModifierForLocalClass, + new String[] {new String(type.sourceName())}, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalModifierForMemberClass(SourceTypeBinding type) { + this.handle( + IProblem.IllegalModifierForMemberClass, + new String[] {new String(type.sourceName())}, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalModifierForMemberInterface(SourceTypeBinding type) { + this.handle( + IProblem.IllegalModifierForMemberInterface, + new String[] {new String(type.sourceName())}, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalModifierForMethod(ReferenceBinding type, AbstractMethodDeclaration methodDecl) { + this.handle( + IProblem.IllegalModifierForMethod, + new String[] {new String(type.sourceName()), new String(methodDecl.selector)}, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void illegalModifierForVariable(LocalDeclaration localDecl, boolean complainAsArgument) { + this.handle( + complainAsArgument + ? IProblem.IllegalModifierForArgument + : IProblem.IllegalModifierForVariable, + new String[] {localDecl.name()}, + localDecl.sourceStart, + localDecl.sourceEnd); +} +public void illegalPrimitiveOrArrayTypeForEnclosingInstance(TypeBinding enclosingType, AstNode location) { + this.handle( + IProblem.IllegalPrimitiveOrArrayTypeForEnclosingInstance, + new String[] {new String(enclosingType.readableName())}, + location.sourceStart, + location.sourceEnd); +} +public void illegalStaticModifierForMemberType(SourceTypeBinding type) { + this.handle( + IProblem.IllegalStaticModifierForMemberType, + new String[] {new String(type.sourceName())}, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalVisibilityModifierCombinationForField(ReferenceBinding type, FieldDeclaration fieldDecl) { + this.handle( + IProblem.IllegalVisibilityModifierCombinationForField, + new String[] {new String(fieldDecl.name())}, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); +} +public void illegalVisibilityModifierCombinationForMemberType(SourceTypeBinding type) { + this.handle( + IProblem.IllegalVisibilityModifierCombinationForMemberType, + new String[] {new String(type.sourceName())}, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalVisibilityModifierCombinationForMethod(ReferenceBinding type, AbstractMethodDeclaration methodDecl) { + this.handle( + IProblem.IllegalVisibilityModifierCombinationForMethod, + new String[] {new String(type.sourceName()), new String(methodDecl.selector)}, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void illegalVisibilityModifierForInterfaceMemberType(SourceTypeBinding type) { + this.handle( + IProblem.IllegalVisibilityModifierForInterfaceMemberType, + new String[] {new String(type.sourceName())}, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalVoidExpression(AstNode location) { + this.handle( + IProblem.InvalidVoidExpression, + new String[] {}, + location.sourceStart, + location.sourceEnd); +} +public void importProblem(ImportReference importRef, Binding expectedImport) { + int problemId = expectedImport.problemId(); + int id; + switch (problemId) { + case NotFound : // 1 + id = IProblem.ImportNotFound; + break; + case NotVisible : // 2 + id = IProblem.ImportNotVisible; + break; + case Ambiguous : // 3 + id = IProblem.ImportAmbiguous; + break; + case InternalNameProvided : // 4 + id = IProblem.ImportInternalNameProvided; + break; + case InheritedNameHidesEnclosingName : // 5 + id = IProblem.ImportInheritedNameHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + return; + } + String argument; + if(expectedImport instanceof ProblemReferenceBinding) { + argument = CharOperation.toString(((ProblemReferenceBinding)expectedImport).compoundName); + } else { + argument = CharOperation.toString(importRef.tokens); + } + this.handle(id, new String[] {argument}, importRef.sourceStart, importRef.sourceEnd); +} +public void incompatibleExceptionInThrowsClause(SourceTypeBinding type, MethodBinding currentMethod, MethodBinding inheritedMethod, ReferenceBinding exceptionType) { + if (type == currentMethod.declaringClass) + this.handle( + // Exception %1 is not compatible with throws clause in %2 + // 9.4.4 - The type of exception in the throws clause is incompatible. + IProblem.IncompatibleExceptionInThrowsClause, + new String[] { + new String(exceptionType.sourceName()), + new String( + CharOperation.concat( + inheritedMethod.declaringClass.readableName(), + inheritedMethod.readableName(), + '.'))}, + currentMethod.sourceStart(), + currentMethod.sourceEnd()); + else + this.handle( + // Exception %1 in throws clause of %2 is not compatible with %3 + // 9.4.4 - The type of exception in the throws clause is incompatible. + IProblem.IncompatibleExceptionInInheritedMethodThrowsClause, + new String[] { + new String(exceptionType.sourceName()), + new String( + CharOperation.concat( + currentMethod.declaringClass.sourceName(), + currentMethod.readableName(), + '.')), + new String( + CharOperation.concat( + inheritedMethod.declaringClass.readableName(), + inheritedMethod.readableName(), + '.'))}, + type.sourceStart(), + type.sourceEnd()); +} +public void incompatibleReturnType(MethodBinding currentMethod, MethodBinding inheritedMethod) { + StringBuffer methodSignature = new StringBuffer(); + methodSignature + .append(inheritedMethod.declaringClass.readableName()) + .append('.') + .append(inheritedMethod.readableName()); + + this.handle( + // Return type is incompatible with %1 + // 9.4.2 - The return type from the method is incompatible with the declaration. + IProblem.IncompatibleReturnType, + new String[] {methodSignature.toString()}, + currentMethod.sourceStart(), + currentMethod.sourceEnd()); +} +public void incorrectEnclosingInstanceReference( + QualifiedThisReference reference, + TypeBinding qualificationType) { + + this.handle( + IProblem.IncorrectEnclosingInstanceReference, + new String[] { new String(qualificationType.readableName())}, + reference.sourceStart, + reference.sourceEnd); +} +public void incorrectLocationForEmptyDimension(ArrayAllocationExpression expression, int index) { + this.handle( + IProblem.IllegalDimension, + new String[0], + expression.dimensions[index + 1].sourceStart, + expression.dimensions[index + 1].sourceEnd); +} +public void incorrectSwitchType(Expression expression, TypeBinding testType) { + this.handle( + IProblem.IncorrectSwitchType, + new String[] {new String(testType.readableName())}, + expression.sourceStart, + expression.sourceEnd); +} +public void inheritedMethodReducesVisibility(SourceTypeBinding type, MethodBinding concreteMethod, MethodBinding[] abstractMethods) { + StringBuffer concreteSignature = new StringBuffer(); + concreteSignature + .append(concreteMethod.declaringClass.readableName()) + .append('.') + .append(concreteMethod.readableName()); + this.handle( + // The inherited method %1 cannot hide the public abstract method in %2 + IProblem.InheritedMethodReducesVisibility, + new String[] { + new String(concreteSignature.toString()), + new String(abstractMethods[0].declaringClass.readableName())}, + type.sourceStart(), + type.sourceEnd()); +} +public void inheritedMethodsHaveIncompatibleReturnTypes(SourceTypeBinding type, MethodBinding[] inheritedMethods, int length) { + StringBuffer methodSignatures = new StringBuffer(); + for (int i = length; --i >= 0;) { + methodSignatures + .append(inheritedMethods[i].declaringClass.readableName()) + .append('.') + .append(inheritedMethods[i].readableName()); + if (i != 0) + methodSignatures.append(", "); //$NON-NLS-1$ + } + + this.handle( + // Return type is incompatible with %1 + // 9.4.2 - The return type from the method is incompatible with the declaration. + IProblem.IncompatibleReturnType, + new String[] {methodSignatures.toString()}, + type.sourceStart(), + type.sourceEnd()); +} +public void initializerMustCompleteNormally(FieldDeclaration fieldDecl) { + this.handle( + IProblem.InitializerMustCompleteNormally, + new String[0], + fieldDecl.sourceStart, + fieldDecl.sourceEnd); +} +public void innerTypesCannotDeclareStaticInitializers(ReferenceBinding innerType, AstNode location) { + this.handle( + IProblem.CannotDefineStaticInitializerInLocalType, + new String[] {new String(innerType.readableName())}, + location.sourceStart, + location.sourceEnd); +} +public void interfaceCannotHaveConstructors(ConstructorDeclaration constructor) { + this.handle( + IProblem.InterfaceCannotHaveConstructors, + new String[0], + constructor.sourceStart, + constructor.sourceEnd, + constructor, + constructor.compilationResult()); +} +public void interfaceCannotHaveInitializers(SourceTypeBinding type, FieldDeclaration fieldDecl) { + this.handle( + IProblem.InterfaceCannotHaveInitializers, + new String[] {new String(type.sourceName())}, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); +} +public void invalidBreak(AstNode location) { + this.handle( + IProblem.InvalidBreak, + new String[0], + location.sourceStart, + location.sourceEnd); +} +public void invalidConstructor(Statement statement, MethodBinding targetConstructor) { + + boolean insideDefaultConstructor = + (referenceContext instanceof ConstructorDeclaration) + && ((ConstructorDeclaration)referenceContext).isDefaultConstructor(); + boolean insideImplicitConstructorCall = + (statement instanceof ExplicitConstructorCall) + && (((ExplicitConstructorCall) statement).accessMode == ExplicitConstructorCall.ImplicitSuper); + + int flag = IProblem.UndefinedConstructor; //default... + switch (targetConstructor.problemId()) { + case NotFound : + if (insideDefaultConstructor){ + flag = IProblem.UndefinedConstructorInDefaultConstructor; + } else if (insideImplicitConstructorCall){ + flag = IProblem.UndefinedConstructorInImplicitConstructorCall; + } else { + flag = IProblem.UndefinedConstructor; + } + break; + case NotVisible : + if (insideDefaultConstructor){ + flag = IProblem.NotVisibleConstructorInDefaultConstructor; + } else if (insideImplicitConstructorCall){ + flag = IProblem.NotVisibleConstructorInImplicitConstructorCall; + } else { + flag = IProblem.NotVisibleConstructor; + } + break; + case Ambiguous : + if (insideDefaultConstructor){ + flag = IProblem.AmbiguousConstructorInDefaultConstructor; + } else if (insideImplicitConstructorCall){ + flag = IProblem.AmbiguousConstructorInImplicitConstructorCall; + } else { + flag = IProblem.AmbiguousConstructor; + } + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + break; + } + + + this.handle( + flag, + new String[] {new String(targetConstructor.declaringClass.readableName()), parametersAsString(targetConstructor)}, + statement.sourceStart, + statement.sourceEnd); +} +public void invalidContinue(AstNode location) { + this.handle( + IProblem.InvalidContinue, + new String[0], + location.sourceStart, + location.sourceEnd); +} +public void invalidEnclosingType(Expression expression, TypeBinding type, TypeBinding enclosingType) { + + int flag = IProblem.UndefinedType; // default + switch (type.problemId()) { + case NotFound : // 1 + flag = IProblem.UndefinedType; + break; + case NotVisible : // 2 + flag = IProblem.NotVisibleType; + break; + case Ambiguous : // 3 + flag = IProblem.AmbiguousType; + break; + case InternalNameProvided : + flag = IProblem.InternalTypeNameProvided; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + break; + } + + this.handle( + flag, + new String[] {new String(enclosingType.readableName()) + "." + new String(type.readableName())}, //$NON-NLS-1$ + expression.sourceStart, + expression.sourceEnd); +} +public void invalidExpressionAsStatement(Expression expression){ + this.handle( + IProblem.InvalidExpressionAsStatement, + new String[0], + expression.sourceStart, + expression.sourceEnd); +} +public void invalidField(FieldReference fieldRef, TypeBinding searchedType) { + int severity = Error; + int flag = IProblem.UndefinedField; + FieldBinding field = fieldRef.binding; + switch (field.problemId()) { + case NotFound : + flag = IProblem.UndefinedField; +/* also need to check that the searchedType is the receiver type + if (searchedType.isHierarchyInconsistent()) + severity = SecondaryError; +*/ + break; + case NotVisible : + flag = IProblem.NotVisibleField; + break; + case Ambiguous : + flag = IProblem.AmbiguousField; + break; + case NonStaticReferenceInStaticContext : + flag = IProblem.NonStaticFieldFromStaticInvocation; + break; + case NonStaticReferenceInConstructorInvocation : + flag = IProblem.InstanceFieldDuringConstructorInvocation; + break; + case InheritedNameHidesEnclosingName : + flag = IProblem.InheritedFieldHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + break; + } + + this.handle( + flag, + new String[] {new String(field.readableName())}, + severity, + fieldRef.sourceStart, + fieldRef.sourceEnd); +} +public void invalidField(NameReference nameRef, FieldBinding field) { + int flag = IProblem.UndefinedField; + switch (field.problemId()) { + case NotFound : + flag = IProblem.UndefinedField; + break; + case NotVisible : + flag = IProblem.NotVisibleField; + break; + case Ambiguous : + flag = IProblem.AmbiguousField; + break; + case NonStaticReferenceInStaticContext : + flag = IProblem.NonStaticFieldFromStaticInvocation; + break; + case NonStaticReferenceInConstructorInvocation : + flag = IProblem.InstanceFieldDuringConstructorInvocation; + break; + case InheritedNameHidesEnclosingName : + flag = IProblem.InheritedFieldHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + break; + } + this.handle( + flag, + new String[] {new String(field.readableName())}, + nameRef.sourceStart, + nameRef.sourceEnd); +} +public void invalidField(QualifiedNameReference nameRef, FieldBinding field, int index, TypeBinding searchedType) { + //the resolution of the index-th field of qname failed + //qname.otherBindings[index] is the binding that has produced the error + + //The different targetted errors should be : + //UndefinedField + //NotVisibleField + //AmbiguousField + + if (searchedType.isBaseType()) { + this.handle( + IProblem.NoFieldOnBaseType, + new String[] { + new String(searchedType.readableName()), + CharOperation.toString(CharOperation.subarray(nameRef.tokens, 0, index)), + new String(nameRef.tokens[index])}, + nameRef.sourceStart, + nameRef.sourceEnd); + return; + } + + int flag = IProblem.UndefinedField; + switch (field.problemId()) { + case NotFound : + flag = IProblem.UndefinedField; +/* also need to check that the searchedType is the receiver type + if (searchedType.isHierarchyInconsistent()) + severity = SecondaryError; +*/ + break; + case NotVisible : + flag = IProblem.NotVisibleField; + break; + case Ambiguous : + flag = IProblem.AmbiguousField; + break; + case NonStaticReferenceInStaticContext : + flag = IProblem.NonStaticFieldFromStaticInvocation; + break; + case NonStaticReferenceInConstructorInvocation : + flag = IProblem.InstanceFieldDuringConstructorInvocation; + break; + case InheritedNameHidesEnclosingName : + flag = IProblem.InheritedFieldHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + break; + } + this.handle( + flag, + new String[] {CharOperation.toString(CharOperation.subarray(nameRef.tokens, 0, index + 1))}, + nameRef.sourceStart, + nameRef.sourceEnd); +} +public void invalidMethod(MessageSend messageSend, MethodBinding method) { + // CODE should be UPDATED according to error coding in the different method binding errors + // The different targetted errors should be : + // UndefinedMethod + // NotVisibleMethod + // AmbiguousMethod + // InheritedNameHidesEnclosingName + // InstanceMethodDuringConstructorInvocation + // StaticMethodRequested + + int flag = IProblem.UndefinedMethod; //default... + switch (method.problemId()) { + case NotFound : + flag = IProblem.UndefinedMethod; + break; + case NotVisible : + flag = IProblem.NotVisibleMethod; + break; + case Ambiguous : + flag = IProblem.AmbiguousMethod; + break; + case InheritedNameHidesEnclosingName : + flag = IProblem.InheritedMethodHidesEnclosingName; + break; + case NonStaticReferenceInConstructorInvocation : + flag = IProblem.InstanceMethodDuringConstructorInvocation; + break; + case NonStaticReferenceInStaticContext : + flag = IProblem.StaticMethodRequested; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + break; + } + + if (flag == IProblem.UndefinedMethod) { + ProblemMethodBinding problemMethod = (ProblemMethodBinding) method; + if (problemMethod.closestMatch != null) { + this.handle( + IProblem.ParameterMismatch, + new String[] { + new String(problemMethod.closestMatch.declaringClass.readableName()), + new String(problemMethod.closestMatch.selector), + parametersAsString(problemMethod.closestMatch), + parametersAsString(method)}, + (int) (messageSend.nameSourcePosition >>> 32), + (int) messageSend.nameSourcePosition); + return; + } + } + + this.handle( + flag, + new String[] { + new String(method.declaringClass.readableName()), + new String(method.selector), parametersAsString(method)}, + (int) (messageSend.nameSourcePosition >>> 32), + (int) messageSend.nameSourcePosition); +} +public void invalidNullToSynchronize(Expression expression) { + this.handle( + IProblem.InvalidNullToSynchronized, + new String[0], + expression.sourceStart, + expression.sourceEnd); +} +public void invalidOperator(BinaryExpression expression, TypeBinding leftType, TypeBinding rightType) { + this.handle( + IProblem.InvalidOperator, + new String[] { + expression.operatorToString(), + new String(leftType.readableName()) + ", " + new String(rightType.readableName())}, //$NON-NLS-1$ + expression.sourceStart, + expression.sourceEnd); +} +public void invalidOperator(CompoundAssignment assign, TypeBinding leftType, TypeBinding rightType) { + this.handle( + IProblem.InvalidOperator, + new String[] { + assign.operatorToString(), + new String(leftType.readableName()) + ", " + new String(rightType.readableName())}, //$NON-NLS-1$ + assign.sourceStart, + assign.sourceEnd); +} +public void invalidOperator(UnaryExpression expression, TypeBinding type) { + this.handle( + IProblem.InvalidOperator, + new String[] {expression.operatorToString(), new String(type.readableName())}, + expression.sourceStart, + expression.sourceEnd); +} +public void invalidSuperclass(SourceTypeBinding type, TypeReference superclassRef, ReferenceBinding expectedType) { + int problemId = expectedType.problemId(); + int id; + switch (problemId) { + case NotFound : // 1 + id = IProblem.SuperclassNotFound; + break; + case NotVisible : // 2 + id = IProblem.SuperclassNotVisible; + break; + case Ambiguous : // 3 + id = IProblem.SuperclassAmbiguous; + break; + case InternalNameProvided : // 4 + id = IProblem.SuperclassInternalNameProvided; + break; + case InheritedNameHidesEnclosingName : // 5 + id = IProblem.SuperclassInheritedNameHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + return; + } + this.handle( + id, + new String[] {new String(expectedType.readableName()), new String(type.sourceName())}, + superclassRef.sourceStart, + superclassRef.sourceEnd); +} +public void invalidSuperinterface(SourceTypeBinding type, TypeReference superinterfaceRef, ReferenceBinding expectedType) { + int problemId = expectedType.problemId(); + int id; + switch (problemId) { + case NotFound : // 1 + id = IProblem.InterfaceNotFound; + break; + case NotVisible : // 2 + id = IProblem.InterfaceNotVisible; + break; + case Ambiguous : // 3 + id = IProblem.InterfaceAmbiguous; + break; + case InternalNameProvided : // 4 + id = IProblem.InterfaceInternalNameProvided; + break; + case InheritedNameHidesEnclosingName : // 5 + id = IProblem.InterfaceInheritedNameHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + return; + } + this.handle( + id, + new String[] {new String(expectedType.readableName()), new String(type.sourceName())}, + superinterfaceRef.sourceStart, + superinterfaceRef.sourceEnd); +} +public void invalidType(AstNode location, TypeBinding type) { + int flag = IProblem.UndefinedType; // default + switch (type.problemId()) { + case NotFound : + flag = IProblem.UndefinedType; + break; + case NotVisible : + flag = IProblem.NotVisibleType; + break; + case Ambiguous : + flag = IProblem.AmbiguousType; + break; + case InternalNameProvided : + flag = IProblem.InternalTypeNameProvided; + break; + case InheritedNameHidesEnclosingName : + flag = IProblem.InheritedTypeHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + break; + } + + this.handle( + flag, + new String[] {new String(type.readableName())}, + location.sourceStart, + location.sourceEnd); +} +public void invalidTypeReference(Expression expression) { + this.handle( + IProblem.InvalidTypeExpression, + new String[0], + expression.sourceStart, + expression.sourceEnd); +} +public void invalidTypeToSynchronize(Expression expression, TypeBinding type) { + this.handle( + IProblem.InvalidTypeToSynchronized, + new String[] {new String(type.readableName())}, + expression.sourceStart, + expression.sourceEnd); +} +public void invalidUnaryExpression(Expression expression) { + this.handle( + IProblem.InvalidUnaryExpression, + new String[0], + expression.sourceStart, + expression.sourceEnd); +} +public void isClassPathCorrect(char[][] wellKnownTypeName, CompilationUnitDeclaration compUnitDecl) { + referenceContext = compUnitDecl; + this.handle( + IProblem.IsClassPathCorrect, + new String[] {CharOperation.toString(wellKnownTypeName)}, + AbortCompilation | Error, + compUnitDecl == null ? 0 : compUnitDecl.sourceStart, + compUnitDecl == null ? 1 : compUnitDecl.sourceEnd); +} +public void maskedExceptionHandler(ReferenceBinding exceptionType, AstNode location) { + this.handle( + IProblem.MaskedCatch, + new String[0], + location.sourceStart, + location.sourceEnd); +} +public void methodNeedingAbstractModifier(MethodDeclaration methodDecl) { + this.handle( + IProblem.MethodRequiresBody, + new String[0], + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void methodNeedingNoBody(MethodDeclaration methodDecl) { + this.handle( + ((methodDecl.modifiers & CompilerModifiers.AccNative) != 0) ? IProblem.BodyForNativeMethod : IProblem.BodyForAbstractMethod, + new String[0], + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void methodWithConstructorName(MethodDeclaration methodDecl) { + this.handle( + IProblem.MethodButWithConstructorName, + new String[0], + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void missingEnclosingInstanceSpecification(ReferenceBinding enclosingType, AstNode location) { + boolean insideConstructorCall = + (location instanceof ExplicitConstructorCall) + && (((ExplicitConstructorCall) location).accessMode == ExplicitConstructorCall.ImplicitSuper); + + this.handle( + insideConstructorCall + ? IProblem.MissingEnclosingInstanceForConstructorCall + : IProblem.MissingEnclosingInstance, + new String[] {new String(enclosingType.readableName())}, + location.sourceStart, + location.sourceEnd); +} +public void missingReturnType(AbstractMethodDeclaration methodDecl) { + this.handle( + IProblem.MissingReturnType, + new String[0], + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void mustDefineDimensionsOrInitializer(ArrayAllocationExpression expression) { + this.handle( + IProblem.MustDefineEitherDimensionExpressionsOrInitializer, + new String[0], + expression.sourceStart, + expression.sourceEnd); +} +public void mustSpecifyPackage(CompilationUnitDeclaration compUnitDecl) { + this.handle( + IProblem.MustSpecifyPackage, + new String[] {new String(compUnitDecl.getFileName())}, + compUnitDecl.sourceStart, + compUnitDecl.sourceStart + 1); +} +public void mustUseAStaticMethod(MessageSend messageSend, MethodBinding method) { + this.handle( + IProblem.StaticMethodRequested, + new String[] {new String(method.declaringClass.readableName()), new String(method.selector), parametersAsString(method)}, + messageSend.sourceStart, + messageSend.sourceEnd); +} +public void nativeMethodsCannotBeStrictfp(ReferenceBinding type, AbstractMethodDeclaration methodDecl) { + this.handle( + IProblem.NativeMethodsCannotBeStrictfp, + new String[] {new String(type.sourceName()), new String(methodDecl.selector)}, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void needImplementation() { + this.abortDueToInternalError(Util.bind("abort.missingCode")); //$NON-NLS-1$ +} +public void needToEmulateFieldReadAccess(FieldBinding field, AstNode location) { + this.handle( + IProblem.NeedToEmulateFieldReadAccess, + new String[] {new String(field.declaringClass.readableName()), new String(field.name)}, + location.sourceStart, + location.sourceEnd); +} +public void needToEmulateFieldWriteAccess(FieldBinding field, AstNode location) { + this.handle( + IProblem.NeedToEmulateFieldWriteAccess, + new String[] {new String(field.declaringClass.readableName()), new String(field.name)}, + location.sourceStart, + location.sourceEnd); +} +public void needToEmulateMethodAccess( + MethodBinding method, + AstNode location) { + + if (method.isConstructor()) + this.handle( + IProblem.NeedToEmulateConstructorAccess, + new String[] { + new String(method.declaringClass.readableName()), + parametersAsString(method) + }, + location.sourceStart, + location.sourceEnd); + else + this.handle( + IProblem.NeedToEmulateMethodAccess, + new String[] { + new String(method.declaringClass.readableName()), + new String(method.selector), + parametersAsString(method) + }, + location.sourceStart, + location.sourceEnd); +} +public void nestedClassCannotDeclareInterface(TypeDeclaration typeDecl) { + this.handle( + IProblem.CannotDefineInterfaceInLocalType, + new String[] {new String(typeDecl.name)}, + typeDecl.sourceStart, + typeDecl.sourceEnd); +} +public void noMoreAvailableSpaceForArgument(LocalVariableBinding local, AstNode location) { + this.handle( + IProblem.TooManyArgumentSlots, + new String[]{ new String(local.name) }, + Abort | Error, + location.sourceStart, + location.sourceEnd); +} +public void noMoreAvailableSpaceForLocal(LocalVariableBinding local, AstNode location) { + this.handle( + IProblem.TooManyLocalVariableSlots, + new String[]{ new String(local.name) }, + Abort | Error, + location.sourceStart, + location.sourceEnd); +} +public void notCompatibleTypesError(EqualExpression expression, TypeBinding leftType, TypeBinding rightType) { + this.handle( + IProblem.IncompatibleTypesInEqualityOperator, + new String[] {new String(leftType.readableName()), new String(rightType.readableName())}, + expression.sourceStart, + expression.sourceEnd); +} +public void notCompatibleTypesError(InstanceOfExpression expression, TypeBinding leftType, TypeBinding rightType) { + this.handle( + IProblem.IncompatibleTypesInConditionalOperator, + new String[] {new String(leftType.readableName()), new String(rightType.readableName())}, + expression.sourceStart, + expression.sourceEnd); +} +public void operatorOnlyValidOnNumericType(CompoundAssignment assignment, TypeBinding leftType, TypeBinding rightType) { + this.handle( + IProblem.TypeMismatch, + new String[] {new String(leftType.readableName()), new String(rightType.readableName())}, + assignment.sourceStart, + assignment.sourceEnd); +} +public void overridesDeprecatedMethod(MethodBinding currentMethod, MethodBinding inheritedMethod) { + this.handle( + IProblem.OverridingDeprecatedMethod, + new String[] {new String(inheritedMethod.declaringClass.readableName())}, + currentMethod.sourceStart(), + currentMethod.sourceEnd()); +} +public void overridesPackageDefaultMethod(MethodBinding localMethod, MethodBinding inheritedMethod) { + this.handle( + IProblem.OverridingNonVisibleMethod, + new String[] { + new String( + CharOperation.concat( + localMethod.declaringClass.readableName(), + localMethod.readableName(), + '.')), + new String(inheritedMethod.declaringClass.readableName())}, + localMethod.sourceStart(), + localMethod.sourceEnd()); +} +public void packageCollidesWithType(CompilationUnitDeclaration compUnitDecl) { + this.handle( + IProblem.PackageCollidesWithType, + new String[] {CharOperation.toString(compUnitDecl.currentPackage.tokens)}, + compUnitDecl.currentPackage.sourceStart, + compUnitDecl.currentPackage.sourceEnd); +} +public void packageIsNotExpectedPackage(CompilationUnitDeclaration compUnitDecl) { + this.handle( + IProblem.PackageIsNotExpectedPackage, + new String[] {CharOperation.toString(compUnitDecl.compilationResult.compilationUnit.getPackageName())}, + compUnitDecl.currentPackage == null ? 0 : compUnitDecl.currentPackage.sourceStart, + compUnitDecl.currentPackage == null ? 0 : compUnitDecl.currentPackage.sourceEnd); +} +private String parametersAsString(MethodBinding method) { + TypeBinding[] params = method.parameters; + StringBuffer buffer = new StringBuffer(); + for (int i = 0, length = params.length; i < length; i++) { + if (i != 0) + buffer.append(", "); //$NON-NLS-1$ + buffer.append(new String(params[i].readableName())); + } + return buffer.toString(); +} +public void parseError( + int startPosition, + int endPosition, + char[] currentTokenSource, + String errorTokenName, + String[] possibleTokens) { + + if (possibleTokens.length == 0) { //no suggestion available + if (isKeyword(currentTokenSource)) { + this.handle( + IProblem.ParsingErrorOnKeywordNoSuggestion, + new String[] {new String(currentTokenSource)}, + // this is the current -invalid- token position + startPosition, + endPosition); + return; + } else { + this.handle( + IProblem.ParsingErrorNoSuggestion, + new String[] {errorTokenName}, + // this is the current -invalid- token position + startPosition, + endPosition); + return; + } + } + + //build a list of probable right tokens + StringBuffer list = new StringBuffer(20); + for (int i = 0, max = possibleTokens.length; i < max; i++) { + if (i > 0) + list.append(", "); //$NON-NLS-1$ + list.append('"'); + list.append(possibleTokens[i]); + list.append('"'); + } + + if (isKeyword(currentTokenSource)) { + this.handle( + IProblem.ParsingErrorOnKeyword, + new String[] {new String(currentTokenSource), list.toString()}, + // this is the current -invalid- token position + startPosition, + endPosition); + return; + } + //extract the literal when it's a literal + if ((errorTokenName.equals("IntegerLiteral")) || //$NON-NLS-1$ + (errorTokenName.equals("LongLiteral")) || //$NON-NLS-1$ + (errorTokenName.equals("FloatingPointLiteral")) || //$NON-NLS-1$ + (errorTokenName.equals("DoubleLiteral")) || //$NON-NLS-1$ + (errorTokenName.equals("StringLiteral")) || //$NON-NLS-1$ + (errorTokenName.equals("CharacterLiteral")) || //$NON-NLS-1$ + (errorTokenName.equals("Identifier"))) { //$NON-NLS-1$ + errorTokenName = new String(currentTokenSource); + } + + this.handle( + IProblem.ParsingError, + new String[] {errorTokenName, list.toString()}, + // this is the current -invalid- token position + startPosition, + endPosition); +} +public void publicClassMustMatchFileName(CompilationUnitDeclaration compUnitDecl, TypeDeclaration typeDecl) { + this.referenceContext = typeDecl; // report the problem against the type not the entire compilation unit + this.handle( + IProblem.PublicClassMustMatchFileName, + new String[] {new String(compUnitDecl.getFileName()), new String(typeDecl.name)}, + typeDecl.sourceStart, + typeDecl.sourceEnd, + compUnitDecl.compilationResult); +} +/* + * Flag all constructors involved in a cycle, we know we have a cycle. + */ +public void recursiveConstructorInvocation(TypeDeclaration typeDeclaration) { + + // propagate the reference count, negative counts means leading to a super constructor invocation (directly or indirectly) + boolean hasChanged; + AbstractMethodDeclaration[] methods = typeDeclaration.methods; + int max = methods.length; + do { + hasChanged = false; + for(int i = 0; i < max; i++){ + if (methods[i].isConstructor()){ + ConstructorDeclaration constructor = (ConstructorDeclaration) methods[i]; + if (constructor.referenceCount > 0){ + ConstructorDeclaration targetConstructor = constructor.constructorCall == null + ? null + : (ConstructorDeclaration)(typeDeclaration.declarationOf(constructor.constructorCall.binding)); + if ((targetConstructor == null) || (targetConstructor.referenceCount < 0)){ + hasChanged = true; + constructor.referenceCount = -1; + } + } + } + } + } while (hasChanged); + + // all remaining constructors with a positive count are still involved in a cycle + for(int i = 0; i < max; i++){ + if (methods[i].isConstructor()){ + ConstructorDeclaration constructor = (ConstructorDeclaration) methods[i]; + if (constructor.referenceCount > 0){ + this.referenceContext = constructor; + this.handle( + IProblem.RecursiveConstructorInvocation, + new String[] { + new String(constructor.constructorCall.binding.declaringClass.readableName()), + parametersAsString(constructor.constructorCall.binding) + }, + constructor.constructorCall.sourceStart, + constructor.constructorCall.sourceEnd); + } + } + } +} +public void redefineArgument(Argument arg) { + this.handle( + IProblem.RedefinedArgument, + new String[] {new String(arg.name)}, + arg.sourceStart, + arg.sourceEnd); +} +public void redefineLocal(LocalDeclaration localDecl) { + this.handle( + IProblem.RedefinedLocal, + new String[] {new String(localDecl.name)}, + localDecl.sourceStart, + localDecl.sourceEnd); +} +public void referenceMustBeArrayTypeAt(TypeBinding arrayType, ArrayReference arrayRef) { + this.handle( + IProblem.ArrayReferenceRequired, + new String[] {new String(arrayType.readableName())}, + arrayRef.sourceStart, + arrayRef.sourceEnd); +} +public void returnTypeCannotBeVoidArray(SourceTypeBinding type, MethodDeclaration methodDecl) { + this.handle( + IProblem.ReturnTypeCannotBeVoidArray, + new String[] {new String(methodDecl.selector)}, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void returnTypeProblem(SourceTypeBinding type, MethodDeclaration methodDecl, TypeBinding expectedType) { + int problemId = expectedType.problemId(); + int id; + switch (problemId) { + case NotFound : // 1 + id = IProblem.ReturnTypeNotFound; + break; + case NotVisible : // 2 + id = IProblem.ReturnTypeNotVisible; + break; + case Ambiguous : // 3 + id = IProblem.ReturnTypeAmbiguous; + break; + case InternalNameProvided : // 4 + id = IProblem.ReturnTypeInternalNameProvided; + break; + case InheritedNameHidesEnclosingName : // 5 + id = IProblem.ReturnTypeInheritedNameHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + return; + } + this.handle( + id, + new String[] {new String(methodDecl.selector), new String(expectedType.readableName())}, + methodDecl.returnType.sourceStart, + methodDecl.returnType.sourceEnd); +} +public void scannerError(Parser parser, String errorTokenName) { + Scanner scanner = parser.scanner; + + int flag = IProblem.ParsingErrorNoSuggestion; + int startPos = scanner.startPosition; + + //special treatment for recognized errors.... + if (errorTokenName.equals(Scanner.END_OF_SOURCE)) + flag = IProblem.EndOfSource; + else + if (errorTokenName.equals(Scanner.INVALID_HEXA)) + flag = IProblem.InvalidHexa; + else + if (errorTokenName.equals(Scanner.INVALID_OCTAL)) + flag = IProblem.InvalidOctal; + else + if (errorTokenName.equals(Scanner.INVALID_CHARACTER_CONSTANT)) + flag = IProblem.InvalidCharacterConstant; + else + if (errorTokenName.equals(Scanner.INVALID_ESCAPE)) + flag = IProblem.InvalidEscape; + else + if (errorTokenName.equals(Scanner.INVALID_UNICODE_ESCAPE)){ + flag = IProblem.InvalidUnicodeEscape; + // better locate the error message + char[] source = scanner.source; + int checkPos = scanner.currentPosition - 1; + if (checkPos >= source.length) checkPos = source.length - 1; + while (checkPos >= startPos){ + if (source[checkPos] == '\\') break; + checkPos --; + } + startPos = checkPos; + } else + if (errorTokenName.equals(Scanner.INVALID_FLOAT)) + flag = IProblem.InvalidFloat; + else + if (errorTokenName.equals(Scanner.UNTERMINATED_STRING)) + flag = IProblem.UnterminatedString; + else + if (errorTokenName.equals(Scanner.UNTERMINATED_COMMENT)) + flag = IProblem.UnterminatedComment; + else + if (errorTokenName.equals(Scanner.INVALID_CHAR_IN_STRING)) + flag = IProblem.UnterminatedString; + + this.handle( + flag, + flag == IProblem.ParsingErrorNoSuggestion + ? new String[] {errorTokenName} + : new String[0], + // this is the current -invalid- token position + startPos, + scanner.currentPosition - 1, + parser.compilationUnit.compilationResult); +} +public void shouldReturn(TypeBinding returnType, AstNode location) { + this.handle( + IProblem.ShouldReturnValue, + new String[] { new String (returnType.readableName())}, + location.sourceStart, + location.sourceEnd); +} +public void signalNoImplicitStringConversionForCharArrayExpression(Expression expression) { + this.handle( + IProblem.NoImplicitStringConversionForCharArrayExpression, + new String[] {}, + expression.sourceStart, + expression.sourceEnd); +} +public void staticAndInstanceConflict(MethodBinding currentMethod, MethodBinding inheritedMethod) { + if (currentMethod.isStatic()) + this.handle( + // This static method cannot hide the instance method from %1 + // 8.4.6.4 - If a class inherits more than one method with the same signature a static (non-abstract) method cannot hide an instance method. + IProblem.CannotHideAnInstanceMethodWithAStaticMethod, + new String[] {new String(inheritedMethod.declaringClass.readableName())}, + currentMethod.sourceStart(), + currentMethod.sourceEnd()); + else + this.handle( + // This instance method cannot override the static method from %1 + // 8.4.6.4 - If a class inherits more than one method with the same signature an instance (non-abstract) method cannot override a static method. + IProblem.CannotOverrideAStaticMethodWithAnInstanceMethod, + new String[] {new String(inheritedMethod.declaringClass.readableName())}, + currentMethod.sourceStart(), + currentMethod.sourceEnd()); +} +public void staticFieldAccessToNonStaticVariable(FieldReference fieldRef, FieldBinding field) { + this.handle( + IProblem.NonStaticFieldFromStaticInvocation, + new String[] {new String(field.readableName())}, + fieldRef.sourceStart, + fieldRef.sourceEnd); +} +public void staticFieldAccessToNonStaticVariable(QualifiedNameReference nameRef, FieldBinding field){ + this.handle( + IProblem.NonStaticFieldFromStaticInvocation, + new String[] { new String(field.readableName())}, + nameRef.sourceStart, + nameRef.sourceEnd); +} +public void staticFieldAccessToNonStaticVariable(SingleNameReference nameRef, FieldBinding field) { + this.handle( + IProblem.NonStaticFieldFromStaticInvocation, + new String[] {new String(field.readableName())}, + nameRef.sourceStart, + nameRef.sourceEnd); +} +public void staticInheritedMethodConflicts(SourceTypeBinding type, MethodBinding concreteMethod, MethodBinding[] abstractMethods) { + this.handle( + // The static method %1 conflicts with the abstract method in %2 + // 8.4.6.4 - If a class inherits more than one method with the same signature it is an error for one to be static (non-abstract) and the other abstract. + IProblem.StaticInheritedMethodConflicts, + new String[] { + new String(concreteMethod.readableName()), + new String(abstractMethods[0].declaringClass.readableName())}, + type.sourceStart(), + type.sourceEnd()); +} +public void stringConstantIsExceedingUtf8Limit(AstNode location) { + this.handle( + IProblem.StringConstantIsExceedingUtf8Limit, + new String[0], + location.sourceStart, + location.sourceEnd); +} +public void superclassMustBeAClass(SourceTypeBinding type, TypeReference superclassRef, ReferenceBinding superType) { + this.handle( + IProblem.SuperclassMustBeAClass, + new String[] {new String(superType.readableName()), new String(type.sourceName())}, + superclassRef.sourceStart, + superclassRef.sourceEnd); +} +public void superinterfaceMustBeAnInterface(SourceTypeBinding type, TypeDeclaration typeDecl, ReferenceBinding superType) { + this.handle( + IProblem.SuperInterfaceMustBeAnInterface, + new String[] {new String(superType.readableName()), new String(type.sourceName())}, + typeDecl.sourceStart, + typeDecl.sourceEnd); +} +public void typeCastError(CastExpression expression, TypeBinding leftType, TypeBinding rightType) { + this.handle( + IProblem.IllegalCast, + new String[] {new String(rightType.readableName()), new String(leftType.readableName())}, + expression.sourceStart, + expression.sourceEnd); +} +public void typeCollidesWithPackage(CompilationUnitDeclaration compUnitDecl, TypeDeclaration typeDecl) { + this.referenceContext = typeDecl; // report the problem against the type not the entire compilation unit + this.handle( + IProblem.TypeCollidesWithPackage, + new String[] {new String(compUnitDecl.getFileName()), new String(typeDecl.name)}, + typeDecl.sourceStart, + typeDecl.sourceEnd, + compUnitDecl.compilationResult); +} +public void typeMismatchError(TypeBinding resultType, TypeBinding expectedType, AstNode location) { + this.handle( + IProblem.TypeMismatch, + new String[] {new String(resultType.readableName()), new String(expectedType.readableName())}, + location.sourceStart, + location.sourceEnd); +} +public void typeMismatchErrorActualTypeExpectedType(Expression expression, TypeBinding constantType, TypeBinding expectedType) { + this.handle( + IProblem.TypeMismatch, + new String[] {new String(constantType.readableName()), new String(expectedType.readableName())}, + expression.sourceStart, + expression.sourceEnd); +} +public void undefinedLabel(BranchStatement statement) { + this.handle( + IProblem.UndefinedLabel, + new String[] {new String(statement.label)}, + statement.sourceStart, + statement.sourceEnd); +} +public void unexpectedStaticModifierForField(SourceTypeBinding type, FieldDeclaration fieldDecl) { + this.handle( + IProblem.UnexpectedStaticModifierForField, + new String[] {fieldDecl.name()}, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); +} +public void unexpectedStaticModifierForMethod(ReferenceBinding type, AbstractMethodDeclaration methodDecl) { + this.handle( + IProblem.UnexpectedStaticModifierForMethod, + new String[] {new String(type.sourceName()), new String(methodDecl.selector)}, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void unhandledException(TypeBinding exceptionType, AstNode location) { + + boolean insideDefaultConstructor = + (referenceContext instanceof ConstructorDeclaration) + && ((ConstructorDeclaration)referenceContext).isDefaultConstructor(); + boolean insideImplicitConstructorCall = + (location instanceof ExplicitConstructorCall) + && (((ExplicitConstructorCall) location).accessMode == ExplicitConstructorCall.ImplicitSuper); + + this.handle( + insideDefaultConstructor + ? IProblem.UnhandledExceptionInDefaultConstructor + : (insideImplicitConstructorCall + ? IProblem.UndefinedConstructorInImplicitConstructorCall + : IProblem.UnhandledException), + new String[] {new String(exceptionType.readableName())}, + location.sourceStart, + location.sourceEnd); +} +public void uninitializedBlankFinalField(FieldBinding binding, AstNode location) { + this.handle( + IProblem.UninitializedBlankFinalField, + new String[] {new String(binding.readableName())}, + location.sourceStart, + location.sourceEnd); +} +public void uninitializedLocalVariable(LocalVariableBinding binding, AstNode location) { + this.handle( + IProblem.UninitializedLocalVariable, + new String[] {new String(binding.readableName())}, + location.sourceStart, + location.sourceEnd); +} +public void unmatchedBracket(int position, ReferenceContext context, CompilationResult compilationResult) { + + this.handle( + IProblem.UnmatchedBracket, + new String[] {}, + position, + position, + context, + compilationResult); +} +public void unnecessaryEnclosingInstanceSpecification(Expression expression, ReferenceBinding targetType) { + this.handle( + IProblem.IllegalEnclosingInstanceSpecification, + new String[]{ new String(targetType.readableName())}, + expression.sourceStart, + expression.sourceEnd); +} +public void unreachableCode(Statement statement) { + this.handle( + IProblem.CodeCannotBeReached, + new String[0], + statement.sourceStart, + statement.sourceEnd); +} +public void unreachableExceptionHandler(ReferenceBinding exceptionType, AstNode location) { + this.handle( + IProblem.UnreachableCatch, + new String[0], + location.sourceStart, + location.sourceEnd); +} +public void unresolvableReference(NameReference nameRef, Binding binding) { + int severity = Error; +/* also need to check that the searchedType is the receiver type + if (binding instanceof ProblemBinding) { + ProblemBinding problem = (ProblemBinding) binding; + if (problem.searchType != null && problem.searchType.isHierarchyInconsistent()) + severity = SecondaryError; + } +*/ + this.handle( + IProblem.UndefinedName, + new String[] {new String(binding.readableName())}, + severity, + nameRef.sourceStart, + nameRef.sourceEnd); +} +public void unusedArgument(LocalDeclaration localDecl) { + this.handle( + IProblem.ArgumentIsNeverUsed, + new String[] {localDecl.name()}, + localDecl.sourceStart, + localDecl.sourceEnd); +} +public void unusedImport(ImportReference importRef) { + this.handle( + IProblem.UnusedImport, + new String[] { CharOperation.toString(importRef.tokens) }, + importRef.sourceStart, + importRef.sourceEnd); +} +public void unusedLocalVariable(LocalDeclaration localDecl) { + this.handle( + IProblem.LocalVariableIsNeverUsed, + new String[] {localDecl.name()}, + localDecl.sourceStart, + localDecl.sourceEnd); +} + +public void useAssertAsAnIdentifier(int sourceStart, int sourceEnd) { + this.handle( + IProblem.UseAssertAsAnIdentifier, + new String[0], + sourceStart, + sourceEnd); +} + +public void variableTypeCannotBeVoid(AbstractVariableDeclaration varDecl) { + this.handle( + IProblem.VariableTypeCannotBeVoid, + new String[] {new String(varDecl.name)}, + varDecl.sourceStart, + varDecl.sourceEnd); +} +public void variableTypeCannotBeVoidArray(AbstractVariableDeclaration varDecl) { + this.handle( + IProblem.VariableTypeCannotBeVoidArray, + new String[] {new String(varDecl.name)}, + varDecl.sourceStart, + varDecl.sourceEnd); +} +public void visibilityConflict(MethodBinding currentMethod, MethodBinding inheritedMethod) { + this.handle( + // Cannot reduce the visibility of the inherited method from %1 + // 8.4.6.3 - The access modifier of an hiding method must provide at least as much access as the hidden method. + // 8.4.6.3 - The access modifier of an overiding method must provide at least as much access as the overriden method. + IProblem.MethodReducesVisibility, + new String[] {new String(inheritedMethod.declaringClass.readableName())}, + currentMethod.sourceStart(), + currentMethod.sourceEnd()); +} +public void wrongSequenceOfExceptionTypesError(TryStatement statement, int under, int upper) { + //the two catch block under and upper are in an incorrect order. + //under should be define BEFORE upper in the source + + //notice that the compiler could arrange automatically the + //correct order - and the only error would be on cycle .... + //on this one again , java is compiler-driven instead of being + //user-driven ..... + + TypeReference typeRef = statement.catchArguments[under].type; + this.handle( + IProblem.UnreachableCatch, + new String[0], + typeRef.sourceStart, + typeRef.sourceEnd); +} + +public void nonExternalizedStringLiteral(AstNode location) { + this.handle( + IProblem.NonExternalizedStringLiteral, + new String[] {}, + location.sourceStart, + location.sourceEnd); +} + +public void noMoreAvailableSpaceInConstantPool(TypeDeclaration typeDeclaration) { + this.handle( + IProblem.TooManyConstantsInConstantPool, + new String[]{ new String(typeDeclaration.binding.readableName())}, + Abort | Error, + typeDeclaration.sourceStart, + typeDeclaration.sourceEnd); +} + +private boolean isKeyword(char[] tokenSource) { + /* + * This code is heavily grammar dependant + */ + + if (tokenSource == null) { + return false; + } + try { + Scanner scanner = new Scanner(); + scanner.setSource(tokenSource); + int token = scanner.getNextToken(); + char[] currentKeyword; + try { + currentKeyword = scanner.getCurrentIdentifierSource(); + } catch (ArrayIndexOutOfBoundsException e) { + return false; + } + int nextToken= scanner.getNextToken(); + if (nextToken == ITerminalSymbols.TokenNameEOF + && scanner.startPosition == scanner.source.length) { // to handle case where we had an ArrayIndexOutOfBoundsException + // while reading the last token + switch(token) { + case Scanner.TokenNameERROR: + if (CharOperation.equals("goto".toCharArray(), currentKeyword) ||CharOperation.equals("const".toCharArray(), currentKeyword)) { //$NON-NLS-1$ //$NON-NLS-2$ + return true; + } else { + return false; + } + case Scanner.TokenNameas: + case Scanner.TokenNameand: +// case Scanner.TokenNameabstract: +// case Scanner.TokenNameassert: +// case Scanner.TokenNamebyte: + case Scanner.TokenNamebreak: +// case Scanner.TokenNameboolean: + case Scanner.TokenNamecase: +// case Scanner.TokenNamechar: +// case Scanner.TokenNamecatch: + case Scanner.TokenNameclass: + case Scanner.TokenNamecontinue: + case Scanner.TokenNamedo: +// case Scanner.TokenNamedouble: + case Scanner.TokenNamedefault: + case Scanner.TokenNameecho: + case Scanner.TokenNameendif: + case Scanner.TokenNameendfor: + case Scanner.TokenNameendforeach: + case Scanner.TokenNameendswitch: + case Scanner.TokenNameendwhile: + case Scanner.TokenNameelse: + case Scanner.TokenNameextends: + case Scanner.TokenNamefor: +// case Scanner.TokenNamefinal: +// case Scanner.TokenNamefloat: + case Scanner.TokenNamefalse: +// case Scanner.TokenNamefinally: + case Scanner.TokenNameglobal: + case Scanner.TokenNameif: + case Scanner.TokenNameinclude: + case Scanner.TokenNameinclude_once: +// case Scanner.TokenNameint: +// case Scanner.TokenNameimport: +// case Scanner.TokenNameinterface: +// case Scanner.TokenNameimplements: +// case Scanner.TokenNameinstanceof: + case Scanner.TokenNamelist: +// case Scanner.TokenNamelong: + case Scanner.TokenNamenew: + case Scanner.TokenNamenull: +// case Scanner.TokenNamenative: + case Scanner.TokenNameold_function: + case Scanner.TokenNameor: + case Scanner.TokenNameprint: +// case Scanner.TokenNamepublic: +// case Scanner.TokenNamepackage: +// case Scanner.TokenNameprivate: +// case Scanner.TokenNameprotected: + case Scanner.TokenNamerequire: + case Scanner.TokenNamerequire_once: + case Scanner.TokenNamereturn: +// case Scanner.TokenNameshort: +// case Scanner.TokenNamesuper: + case Scanner.TokenNamestatic: + case Scanner.TokenNameswitch: +// case Scanner.TokenNamestrictfp: +// case Scanner.TokenNamesynchronized: +// case Scanner.TokenNametry: +// case Scanner.TokenNamethis: + case Scanner.TokenNametrue: +// case Scanner.TokenNamethrow: +// case Scanner.TokenNamethrows: +// case Scanner.TokenNametransient: + case Scanner.TokenNamevar: +// case Scanner.TokenNamevoid: +// case Scanner.TokenNamevolatile: + case Scanner.TokenNamewhile: + case Scanner.TokenNamexor: + return true; + default: + return false; + } + } else { + return false; + } + } + catch (InvalidInputException e) { + return false; + } + +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/ProblemSeverities.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/ProblemSeverities.java new file mode 100644 index 0000000..cc46b65 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/ProblemSeverities.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.problem; + +public interface ProblemSeverities { + + final int Ignore = -1; // during handling only + final int Warning = 0; // during handling only + + final int Error = 1; // when bit is set: problem is error, if not it is a warning + final int AbortCompilation = 2; + final int AbortCompilationUnit = 4; + final int AbortType = 8; + final int AbortMethod = 16; + final int Abort = 30; // 2r11110 + final int SecondaryError = 64; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/ShouldNotImplement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/ShouldNotImplement.java new file mode 100644 index 0000000..633cfea --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/problem/ShouldNotImplement.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.problem; + +/* + * Special unchecked exception type used + * to denote implementation that should never be reached. + * + * (internal only) + */ +public class ShouldNotImplement extends RuntimeException { +public ShouldNotImplement(){ +} +public ShouldNotImplement(String message){ + super(message); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/CharOperation.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/CharOperation.java new file mode 100644 index 0000000..64577f9 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/CharOperation.java @@ -0,0 +1,703 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.util; + +import net.sourceforge.phpdt.internal.compiler.lookup.TypeConstants; + +public final class CharOperation { + +public static final char[] append(char[] array, char suffix){ + if (array == null) return new char[]{suffix}; + int length = array.length; + System.arraycopy(array, 0, array = new char[length+1], 0, length); + array[length]=suffix; + return array; +} + +public static final char[][] arrayConcat(char[][] first, char[][] second) { + if (first == null) + return second; + if (second == null) + return first; + + int length1 = first.length; + int length2 = second.length; + char[][] result = new char[length1 + length2][]; +/* if we do not trust System.arraycopy on our VM with char[][]'s + int i; + for (i = 0; i < length1; i++) + result[i] = first[i]; + for (int j = 0; j < length2; j++) + result[i++] = second[j]; +*/ + System.arraycopy(first, 0, result, 0, length1); + System.arraycopy(second, 0, result, length1, length2); + return result; +} +public static final char[][] arrayConcat(char[][] first, char[] second) { + if (second == null) + return first; + if (first == null) + return new char[][] {second}; + + int length = first.length; + char[][] result = new char[length + 1][]; +/* if we do not trust System.arraycopy on our VM with char[][]'s + for (int i = 0; i < length; i++) + result[i] = first[i]; +*/ + System.arraycopy(first, 0, result, 0, length); + result[length] = second; + return result; +} +public static final char[] concat(char[] first, char[] second) { + if (first == null) + return second; + if (second == null) + return first; + + int length1 = first.length; + int length2 = second.length; + char[] result = new char[length1 + length2]; + System.arraycopy(first, 0, result, 0, length1); + System.arraycopy(second, 0, result, length1, length2); + return result; +} +public static final char[] concat(char[] first, char[] second, char[] third) { + if (first == null) + return concat(second, third); + if (second == null) + return concat(first, third); + if (third == null) + return concat(first, second); + + int length1 = first.length; + int length2 = second.length; + int length3 = third.length; + char[] result = new char[length1 + length2 + length3]; + System.arraycopy(first, 0, result, 0, length1); + System.arraycopy(second, 0, result, length1, length2); + System.arraycopy(third, 0, result, length1 + length2, length3); + return result; +} +public static final char[] concat(char[] first, char[] second, char separator) { + if (first == null) + return second; + if (second == null) + return first; + + int length1 = first.length; + if (length1 == 0) + return second; + int length2 = second.length; + if (length2 == 0) + return first; + + char[] result = new char[length1 + length2 + 1]; + System.arraycopy(first, 0, result, 0, length1); + result[length1] = separator; + System.arraycopy(second, 0, result, length1 + 1, length2); + return result; +} +public static final char[] concat(char[] first, char sep1, char[] second, char sep2, char[] third) { + if (first == null) + return concat(second, third, sep2); + if (second == null) + return concat(first, third, sep1); + if (third == null) + return concat(first, second, sep1); + + int length1 = first.length; + int length2 = second.length; + int length3 = third.length; + char[] result = new char[length1 + length2 + length3 + 2]; + System.arraycopy(first, 0, result, 0, length1); + result[length1] = sep1; + System.arraycopy(second, 0, result, length1 + 1, length2); + result[length1+length2+1] = sep2; + System.arraycopy(third, 0, result, length1 + length2 + 2, length3); + return result; +} +public static final char[] concat(char prefix, char[] array, char suffix) { + if (array == null) + return new char[] {prefix, suffix}; + + int length = array.length; + char[] result = new char[length + 2]; + result[0] = prefix; + System.arraycopy(array, 0, result, 1, length); + result[length + 1] = suffix; + return result; +} +public static final char[] concatWith(char[] name, char[][] array, char separator) { + int nameLength = name == null ? 0 : name.length; + if (nameLength == 0) + return concatWith(array, separator); + + int length = array == null ? 0 : array.length; + if (length == 0) + return name; + + int size = nameLength; + int index = length; + while (--index >= 0) + if (array[index].length > 0) + size += array[index].length + 1; + char[] result = new char[size]; + index = size; + for (int i = length-1; i >= 0; i--) { + int subLength = array[i].length; + if (subLength > 0) { + index -= subLength; + System.arraycopy(array[i], 0, result, index, subLength); + result[--index] = separator; + } + } + System.arraycopy(name, 0, result, 0, nameLength); + return result; +} +public static final char[] concatWith(char[][] array, char[] name, char separator) { + int nameLength = name == null ? 0 : name.length; + if (nameLength == 0) + return concatWith(array, separator); + + int length = array == null ? 0 : array.length; + if (length == 0) + return name; + + int size = nameLength; + int index = length; + while (--index >= 0) + if (array[index].length > 0) + size += array[index].length + 1; + char[] result = new char[size]; + index = 0; + for (int i = 0; i < length; i++) { + int subLength = array[i].length; + if (subLength > 0) { + System.arraycopy(array[i], 0, result, index, subLength); + index += subLength; + result[index++] = separator; + } + } + System.arraycopy(name, 0, result, index, nameLength); + return result; +} +public static final char[] concatWith(char[][] array, char separator) { + int length = array == null ? 0 : array.length; + if (length == 0) + return TypeConstants.NoChar; + + int size = length - 1; + int index = length; + while (--index >= 0) { + if (array[index].length == 0) + size--; + else + size += array[index].length; + } + if (size <= 0) + return TypeConstants.NoChar; + char[] result = new char[size]; + index = length; + while (--index >= 0) { + length = array[index].length; + if (length > 0) { + System.arraycopy(array[index], 0, result, (size -= length), length); + if (--size >= 0) + result[size] = separator; + } + } + return result; +} +public static final boolean contains(char character, char[][] array) { + for (int i = array.length; --i >= 0;) { + char[] subarray = array[i]; + for (int j = subarray.length; --j >= 0;) + if (subarray[j] == character) + return true; + } + return false; +} +public static final boolean contains(char character, char[] array) { + for (int i = array.length; --i >= 0;) + if (array[i] == character) + return true; + return false; +} +public static final char[][] deepCopy(char[][] toCopy) { + int toCopyLength = toCopy.length; + char[][] result = new char[toCopyLength][]; + for (int i = 0; i < toCopyLength; i++) { + char[] toElement = toCopy[i]; + int toElementLength = toElement.length; + char[] resultElement = new char[toElementLength]; + System.arraycopy(toElement, 0, resultElement, 0, toElementLength); + result[i] = resultElement; + } + return result; +} + +public static final boolean endsWith(char[] array, char[] toBeFound) { + int i = toBeFound.length; + int j = array.length - i; + + if (j < 0) + return false; + while (--i >= 0) + if (toBeFound[i] != array[i + j]) + return false; + return true; +} + +public static final boolean equals(char[][] first, char[][] second) { + if (first == second) + return true; + if (first == null || second == null) + return false; + if (first.length != second.length) + return false; + + for (int i = first.length; --i >= 0;) + if (!equals(first[i], second[i])) + return false; + return true; +} +public static final boolean equals(char[][] first, char[][] second, boolean isCaseSensitive) { + + if (isCaseSensitive){ + return equals(first, second); + } + if (first == second) + return true; + if (first == null || second == null) + return false; + if (first.length != second.length) + return false; + + for (int i = first.length; --i >= 0;) + if (!equals(first[i], second[i], false)) + return false; + return true; +} +public static final boolean equals(char[] first, char[] second) { + if (first == second) + return true; + if (first == null || second == null) + return false; + if (first.length != second.length) + return false; + + for (int i = first.length; --i >= 0;) + if (first[i] != second[i]) + return false; + return true; +} +public static final boolean equals(char[] first, char[] second, boolean isCaseSensitive) { + + if (isCaseSensitive){ + return equals(first, second); + } + if (first == second) + return true; + if (first == null || second == null) + return false; + if (first.length != second.length) + return false; + + for (int i = first.length; --i >= 0;) + if (Character.toLowerCase(first[i]) != Character.toLowerCase(second[i])) + return false; + return true; +} +public static final boolean fragmentEquals(char[] fragment, char[] name, int startIndex, boolean isCaseSensitive) { + + int max = fragment.length; + if (name.length < max+startIndex) return false; + if (isCaseSensitive){ + for (int i = max; --i >= 0;) // assumes the prefix is not larger than the name + if (fragment[i] != name[i + startIndex]) + return false; + return true; + } + for (int i = max; --i >= 0;) // assumes the prefix is not larger than the name + if (Character.toLowerCase(fragment[i]) != Character.toLowerCase(name[i + startIndex])) + return false; + return true; +} +public static final int hashCode(char[] array) { + int hash = 0; + int offset = 0; + int length = array.length; + if (length < 16) { + for (int i = length; i > 0; i--) + hash = (hash * 37) + array[offset++]; + } else { + // only sample some characters + int skip = length / 8; + for (int i = length; i > 0; i -= skip, offset += skip) + hash = (hash * 39) + array[offset]; + } + return hash & 0x7FFFFFFF; +} +public static final int indexOf(char toBeFound, char[] array) { + for (int i = 0; i < array.length; i++) + if (toBeFound == array[i]) + return i; + return -1; +} +public static final int indexOf(char toBeFound, char[] array, int start) { + for (int i = start; i < array.length; i++) + if (toBeFound == array[i]) + return i; + return -1; +} +public static final int lastIndexOf(char toBeFound, char[] array) { + for (int i = array.length; --i >= 0;) + if (toBeFound == array[i]) + return i; + return -1; +} +public static final int lastIndexOf(char toBeFound, char[] array, int startIndex) { + for (int i = array.length; --i >= startIndex;) + if (toBeFound == array[i]) + return i; + return -1; +} +public static final int lastIndexOf(char toBeFound, char[] array, int startIndex, int endIndex) { + for (int i = endIndex; --i >= startIndex;) + if (toBeFound == array[i]) + return i; + return -1; +} +/** + * Answer the last portion of a name given a separator + * e.g. lastSegment("java.lang.Object".toCharArray(),'.') --> Object + */ +final static public char[] lastSegment(char[] array, char separator) { + int pos = lastIndexOf(separator, array); + if (pos < 0) return array; + return subarray(array, pos+1, array.length); +} +/** + * char[] pattern matching, accepting wild-cards '*'. + * + * When not case sensitive, the pattern is assumed to already be lowercased, the + * name will be lowercased character per character as comparing. + */ +public static final boolean match(char[] pattern, char[] name, boolean isCaseSensitive) { + + if (name == null) return false; // null name cannot match + if (pattern == null) return true; // null pattern is equivalent to '*' + int iPattern = 0, patternLength = pattern.length; + int iName = 0, nameLength = name.length; + + /* check first segment */ + char patternChar = 0; + while ((iPattern < patternLength) && (patternChar = pattern[iPattern]) != '*'){ + if (iName == nameLength) return false; + if (patternChar != (isCaseSensitive + ? name[iName] + : Character.toLowerCase(name[iName]))){ + return false; + } + iName++; + iPattern++; + } + /* check sequence of star+segment */ + int segmentStart; + if (patternChar == '*'){ + segmentStart = ++iPattern; // skip star + } else { + segmentStart = 0; // force iName check + } + int prefixStart = iName; + checkSegment: while (iName < nameLength && iPattern < patternLength){ + /* segment is ending */ + if ((patternChar = pattern[iPattern]) == '*'){ + segmentStart = ++iPattern; // skip start + prefixStart = iName; + continue checkSegment; + } + /* chech current name character */ + if ((isCaseSensitive + ? name[iName] + : Character.toLowerCase(name[iName]))!= patternChar){ + iPattern = segmentStart; // mismatch - restart current segment + iName = ++prefixStart; + continue checkSegment; + } + iName++; + iPattern++; + } + + return (segmentStart == patternLength) + || (iName == nameLength && iPattern == patternLength) + || (iPattern == patternLength - 1 && pattern[iPattern] == '*'); +} +public static final int occurencesOf(char toBeFound, char[] array) { + int count = 0; + for (int i = 0; i < array.length; i++) + if (toBeFound == array[i]) count++; + return count; +} +public static final int occurencesOf(char toBeFound, char[] array, int start) { + int count = 0; + for (int i = start; i < array.length; i++) + if (toBeFound == array[i]) count++; + return count; +} +public static final boolean prefixEquals(char[] prefix, char[] name) { + + int max = prefix.length; + if (name.length < max) return false; + for (int i = max; --i >= 0;) // assumes the prefix is not larger than the name + if (prefix[i] != name[i]) + return false; + return true; +} +public static final boolean prefixEquals(char[] prefix, char[] name, boolean isCaseSensitive) { + + int max = prefix.length; + if (name.length < max) return false; + if (isCaseSensitive){ + for (int i = max; --i >= 0;) // assumes the prefix is not larger than the name + if (prefix[i] != name[i]) + return false; + return true; + } + + for (int i = max; --i >= 0;) // assumes the prefix is not larger than the name + if (Character.toLowerCase(prefix[i]) != Character.toLowerCase(name[i])) + return false; + return true; +} +public static final void replace( + char[] array, + char toBeReplaced, + char replacementChar) { + if (toBeReplaced != replacementChar) { + for (int i = 0, max = array.length; i < max; i++) { + if (array[i] == toBeReplaced) + array[i] = replacementChar; + } + } +} + +/* + * Returns a char[] with substitutions. No side-effect is operated on the original + * array, in case no substitution happened, then the result might be the same as the + * original one. + * + */ +public static final char[] replace( + char[] array, + char[] toBeReplaced, + char[] replacementChars) { + + + int max = array.length; + int replacedLength = toBeReplaced.length; + int replacementLength = replacementChars.length; + + int[] starts = new int[5]; + int occurrenceCount = 0; + + if (!equals(toBeReplaced,replacementChars)) { + + next: for (int i = 0; i < max; i++) { + int j = 0; + while (j < replacedLength){ + if (i+j == max) continue next; + if (array[i + j] != toBeReplaced[j++]) continue next; + } + if (occurrenceCount == starts.length){ + System.arraycopy(starts, 0, starts = new int[occurrenceCount * 2], 0, occurrenceCount); + } + starts[occurrenceCount++] = i; + } + } + if (occurrenceCount == 0) return array; + char[] result = new char[max + occurrenceCount * (replacementLength - replacedLength)]; + int inStart = 0, outStart = 0; + for( int i = 0; i < occurrenceCount; i++){ + int offset = starts[i] - inStart; + System.arraycopy(array, inStart, result, outStart, offset); + inStart += offset; + outStart += offset; + System.arraycopy(replacementChars, 0, result, outStart, replacementLength); + inStart += replacedLength; + outStart += replacementLength; + } + System.arraycopy(array, inStart, result, outStart, max - inStart); + return result; +} + +public static final char[][] splitAndTrimOn(char divider, char[] array) { + int length = array == null ? 0 : array.length; + if (length == 0) + return TypeConstants.NoCharChar; + + int wordCount = 1; + for (int i = 0; i < length; i++) + if (array[i] == divider) + wordCount++; + char[][] split = new char[wordCount][]; + int last = 0, currentWord = 0; + for (int i = 0; i < length; i++) { + if (array[i] == divider) { + int start = last, end = i - 1; + while (start < i && array[start] == ' ') start++; + while (end > start && array[end] == ' ') end--; + split[currentWord] = new char[end - start + 1]; + System.arraycopy(array, start, split[currentWord++], 0, end - start + 1); + last = i + 1; + } + } + int start = last, end = length - 1; + while (start < length && array[start] == ' ') start++; + while (end > start && array[end] == ' ') end--; + split[currentWord] = new char[end - start + 1]; + System.arraycopy(array, start, split[currentWord++], 0, end - start + 1); + return split; +} + +public static final char[][] splitOn(char divider, char[] array) { + int length = array == null ? 0 : array.length; + if (length == 0) + return TypeConstants.NoCharChar; + + int wordCount = 1; + for (int i = 0; i < length; i++) + if (array[i] == divider) + wordCount++; + char[][] split = new char[wordCount][]; + int last = 0, currentWord = 0; + for (int i = 0; i < length; i++) { + if (array[i] == divider) { + split[currentWord] = new char[i - last]; + System.arraycopy(array, last, split[currentWord++], 0, i - last); + last = i + 1; + } + } + split[currentWord] = new char[length - last]; + System.arraycopy(array, last, split[currentWord], 0, length - last); + return split; +} +public static final char[][] splitOn(char divider, char[] array, int start, int end) { + int length = array == null ? 0 : array.length; + if (length == 0 || start > end) + return TypeConstants.NoCharChar; + + int wordCount = 1; + for (int i = start; i < end; i++) + if (array[i] == divider) + wordCount++; + char[][] split = new char[wordCount][]; + int last = start, currentWord = 0; + for (int i = start; i < end; i++) { + if (array[i] == divider) { + split[currentWord] = new char[i - last]; + System.arraycopy(array, last, split[currentWord++], 0, i - last); + last = i + 1; + } + } + split[currentWord] = new char[end - last + 1]; + System.arraycopy(array, last, split[currentWord], 0, end - last + 1); + return split; +} +public static final boolean startsWith(char[] array, char[] toBeFound) { + int i = toBeFound.length; + if (i > array.length) + return false; + while (--i >= 0) + if (toBeFound[i] != array[i]) + return false; + return true; +} +/* + * copies from array[start] through array[end - 1] (does not copy array[end]) + */ +public static final char[][] subarray(char[][] array, int start, int end) { + if (end == -1) end = array.length; + if (start > end) return null; + if (start < 0) return null; + if (end > array.length) return null; + + char[][] result = new char[end - start][]; +/* if we do not trust System.arraycopy on our VM with char[][]'s + for (int i = 0, s = start; s < end; i++, s++) + result[i] = array[s]; +*/ + System.arraycopy(array, start, result, 0, end - start); + return result; +} +/* + * copies from array[start] through array[end - 1] (does not copy array[end]) + */ +public static final char[] subarray(char[] array, int start, int end) { + if (end == -1) end = array.length; + if (start > end) return null; + if (start < 0) return null; + if (end > array.length) return null; + + char[] result = new char[end - start]; + System.arraycopy(array, start, result, 0, end - start); + return result; +} +/** + * Answers the result of a char[] conversion to lowercase. + * NOTE: if no conversion was necessary, then answers back the argument one. + */ +final static public char[] toLowerCase(char[] chars) { + if (chars == null) return null; + int length = chars.length; + char[] lowerChars = null; + for (int i = 0; i < length; i++){ + char c = chars[i]; + char lc = Character.toLowerCase(c); + if ((c != lc) || (lowerChars != null)){ + if (lowerChars == null){ + System.arraycopy(chars, 0, lowerChars = new char[length], 0, i); + } + lowerChars[i] = lc; + } + } + return lowerChars == null ? chars : lowerChars; +} + +/** + * Remove leading and trailing spaces + */ +final static public char[] trim(char[] chars){ + + if (chars == null) return null; + + char[] result = chars; + int start = 0, length = chars.length, end = length - 1; + while (start < length && chars[start] == ' ') { + start++; + } + while (end > start && chars[end] == ' '){ + end--; + } + if (start != 0 || end != length - 1){ + return subarray(chars, start, end+1); + } + return chars; +} +final static public String toString(char[][] array) { + char[] result = concatWith(array, '.'); + if (result == null) + return ""; //$NON-NLS-1$ + return new String(result); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/CompoundNameVector.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/CompoundNameVector.java new file mode 100644 index 0000000..7779af6 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/CompoundNameVector.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.util; + +public final class CompoundNameVector { + static int INITIAL_SIZE = 10; + + public int size; + int maxSize; + char[][][] elements; +public CompoundNameVector() { + maxSize = INITIAL_SIZE; + size = 0; + elements = new char[maxSize][][]; +} +public void add(char[][] newElement) { + if (size == maxSize) // knows that size starts <= maxSize + System.arraycopy(elements, 0, (elements = new char[maxSize *= 2][][]), 0, size); + elements[size++] = newElement; +} +public void addAll(char[][][] newElements) { + if (size + newElements.length >= maxSize) { + maxSize = size + newElements.length; // assume no more elements will be added + System.arraycopy(elements, 0, (elements = new char[maxSize][][]), 0, size); + } + System.arraycopy(newElements, 0, elements, size, newElements.length); + size += newElements.length; +} +public boolean contains(char[][] element) { + for (int i = size; --i >= 0;) + if (CharOperation.equals(element, elements[i])) + return true; + return false; +} +public char[][] elementAt(int index) { + return elements[index]; +} +public char[][] remove(char[][] element) { + // assumes only one occurrence of the element exists + for (int i = size; --i >= 0;) + if (element == elements[i]) { + // shift the remaining elements down one spot + System.arraycopy(elements, i + 1, elements, i, --size - i); + elements[size] = null; + return element; + } + return null; +} +public void removeAll() { + for (int i = size; --i >= 0;) + elements[i] = null; + size = 0; +} +public String toString() { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < size; i++) { + buffer.append(CharOperation.toString(elements[i])).append("\n"); //$NON-NLS-1$ + } + return buffer.toString(); +} +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/HashtableOfInt.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/HashtableOfInt.java new file mode 100644 index 0000000..9a31f91 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/HashtableOfInt.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.util; + + /** + * Hashtable for non-zero int keys. + */ + +public final class HashtableOfInt { + // to avoid using Enumerations, walk the individual tables skipping nulls + public int[] keyTable; + public Object[] valueTable; + + int elementSize; // number of elements in the table + int threshold; +public HashtableOfInt() { + this(13); +} +public HashtableOfInt(int size) { + this.elementSize = 0; + this.threshold = size; // size represents the expected number of elements + int extraRoom = (int) (size * 1.75f); + if (this.threshold == extraRoom) + extraRoom++; + this.keyTable = new int[extraRoom]; + this.valueTable = new Object[extraRoom]; +} +public boolean containsKey(int key) { + int index = key % valueTable.length; + int currentKey; + while ((currentKey = keyTable[index]) != 0) { + if (currentKey == key) + return true; + index = (index + 1) % keyTable.length; + } + return false; +} +public Object get(int key) { + int index = key % valueTable.length; + int currentKey; + while ((currentKey = keyTable[index]) != 0) { + if (currentKey == key) return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return null; +} +public Object put(int key, Object value) { + int index = key % valueTable.length; + int currentKey; + while ((currentKey = keyTable[index]) != 0) { + if (currentKey == key) return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) + rehash(); + return value; +} +private void rehash() { + HashtableOfInt newHashtable = new HashtableOfInt(elementSize * 2); // double the number of expected elements + int currentKey; + for (int i = keyTable.length; --i >= 0;) + if ((currentKey = keyTable[i]) != 0) + newHashtable.put(currentKey, valueTable[i]); + + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; +} +public int size() { + return elementSize; +} +public String toString() { + String s = ""; //$NON-NLS-1$ + Object object; + for (int i = 0, length = valueTable.length; i < length; i++) + if ((object = valueTable[i]) != null) + s += keyTable[i] + " -> " + object.toString() + "\n"; //$NON-NLS-2$ //$NON-NLS-1$ + return s; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/HashtableOfObject.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/HashtableOfObject.java new file mode 100644 index 0000000..c59958a --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/HashtableOfObject.java @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.util; + +/** + * Hashtable of {char[] --> Object } + */ +public final class HashtableOfObject implements Cloneable { + + // to avoid using Enumerations, walk the individual tables skipping nulls + public char[] keyTable[]; + public Object valueTable[]; + + public int elementSize; // number of elements in the table + int threshold; + + public HashtableOfObject() { + this(13); + } + + public HashtableOfObject(int size) { + + this.elementSize = 0; + this.threshold = size; // size represents the expected number of elements + int extraRoom = (int) (size * 1.75f); + if (this.threshold == extraRoom) + extraRoom++; + this.keyTable = new char[extraRoom][]; + this.valueTable = new Object[extraRoom]; + } + + public Object clone() throws CloneNotSupportedException { + HashtableOfObject result = (HashtableOfObject) super.clone(); + result.elementSize = this.elementSize; + result.threshold = this.threshold; + + int length = this.keyTable.length; + result.keyTable = new char[length][]; + System.arraycopy(this.keyTable, 0, result.keyTable, 0, length); + + length = this.valueTable.length; + result.valueTable = new Object[length]; + System.arraycopy(this.valueTable, 0, result.valueTable, 0, length); + return result; + } + + public boolean containsKey(char[] key) { + + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength + && CharOperation.prefixEquals(currentKey, key)) + return true; + index = (index + 1) % keyTable.length; + } + return false; + } + + public Object get(char[] key) { + + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength + && CharOperation.prefixEquals(currentKey, key)) + return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return null; + } + + public Object put(char[] key, Object value) { + + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength + && CharOperation.prefixEquals(currentKey, key)) + return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) + rehash(); + return value; + } + + public Object removeKey(char[] key) { + + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength + && CharOperation.prefixEquals(currentKey, key)) { + Object value = valueTable[index]; + elementSize--; + keyTable[index] = null; + valueTable[index] = null; + rehash(); + return value; + } + index = (index + 1) % keyTable.length; + } + return null; + } + + private void rehash() { + + HashtableOfObject newHashtable = new HashtableOfObject(elementSize * 2); // double the number of expected elements + char[] currentKey; + for (int i = keyTable.length; --i >= 0;) + if ((currentKey = keyTable[i]) != null) + newHashtable.put(currentKey, valueTable[i]); + + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; + } + + public int size() { + return elementSize; + } + + public String toString() { + String s = ""; //$NON-NLS-1$ + Object object; + for (int i = 0, length = valueTable.length; i < length; i++) + if ((object = valueTable[i]) != null) + s += new String(keyTable[i]) + " -> " + object.toString() + "\n"; //$NON-NLS-2$ //$NON-NLS-1$ + return s; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/HashtableOfPackage.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/HashtableOfPackage.java new file mode 100644 index 0000000..906e0ec --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/HashtableOfPackage.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.util; + +import net.sourceforge.phpdt.internal.compiler.lookup.PackageBinding; + +public final class HashtableOfPackage { + // to avoid using Enumerations, walk the individual tables skipping nulls + public char[] keyTable[]; + public PackageBinding valueTable[]; + + int elementSize; // number of elements in the table + int threshold; +public HashtableOfPackage() { + this(3); // usually not very large +} +public HashtableOfPackage(int size) { + this.elementSize = 0; + this.threshold = size; // size represents the expected number of elements + int extraRoom = (int) (size * 1.75f); + if (this.threshold == extraRoom) + extraRoom++; + this.keyTable = new char[extraRoom][]; + this.valueTable = new PackageBinding[extraRoom]; +} +public boolean containsKey(char[] key) { + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.prefixEquals(currentKey, key)) + return true; + index = (index + 1) % keyTable.length; + } + return false; +} +public PackageBinding get(char[] key) { + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.prefixEquals(currentKey, key)) + return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return null; +} +public PackageBinding put(char[] key, PackageBinding value) { + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.prefixEquals(currentKey, key)) + return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) + rehash(); + return value; +} +private void rehash() { + HashtableOfPackage newHashtable = new HashtableOfPackage(elementSize * 2); // double the number of expected elements + char[] currentKey; + for (int i = keyTable.length; --i >= 0;) + if ((currentKey = keyTable[i]) != null) + newHashtable.put(currentKey, valueTable[i]); + + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; +} +public int size() { + return elementSize; +} +public String toString() { + String s = ""; //$NON-NLS-1$ + PackageBinding pkg; + for (int i = 0, length = valueTable.length; i < length; i++) + if ((pkg = valueTable[i]) != null) + s += pkg.toString() + "\n"; //$NON-NLS-1$ + return s; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/HashtableOfType.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/HashtableOfType.java new file mode 100644 index 0000000..322a2d1 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/HashtableOfType.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.util; + +import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding; + +public final class HashtableOfType { + // to avoid using Enumerations, walk the individual tables skipping nulls + public char[] keyTable[]; + public ReferenceBinding valueTable[]; + + int elementSize; // number of elements in the table + int threshold; +public HashtableOfType() { + this(3); +} +public HashtableOfType(int size) { + this.elementSize = 0; + this.threshold = size; // size represents the expected number of elements + int extraRoom = (int) (size * 1.75f); + if (this.threshold == extraRoom) + extraRoom++; + this.keyTable = new char[extraRoom][]; + this.valueTable = new ReferenceBinding[extraRoom]; +} +public boolean containsKey(char[] key) { + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.prefixEquals(currentKey, key)) + return true; + index = (index + 1) % keyTable.length; + } + return false; +} +public ReferenceBinding get(char[] key) { + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.prefixEquals(currentKey, key)) + return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return null; +} +public ReferenceBinding put(char[] key, ReferenceBinding value) { + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.prefixEquals(currentKey, key)) + return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) + rehash(); + return value; +} +private void rehash() { + HashtableOfType newHashtable = new HashtableOfType(elementSize < 100 ? 100 : elementSize * 2); // double the number of expected elements + char[] currentKey; + for (int i = keyTable.length; --i >= 0;) + if ((currentKey = keyTable[i]) != null) + newHashtable.put(currentKey, valueTable[i]); + + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; +} +public int size() { + return elementSize; +} +public String toString() { + String s = ""; //$NON-NLS-1$ + ReferenceBinding type; + for (int i = 0, length = valueTable.length; i < length; i++) + if ((type = valueTable[i]) != null) + s += type.toString() + "\n"; //$NON-NLS-1$ + return s; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/ObjectVector.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/ObjectVector.java new file mode 100644 index 0000000..ff75c47 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/ObjectVector.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.util; + +public final class ObjectVector { + + static int INITIAL_SIZE = 10; + + public int size; + int maxSize; + Object[] elements; + + public ObjectVector() { + + this.maxSize = INITIAL_SIZE; + this.size = 0; + this.elements = new Object[this.maxSize]; + } + + public void add(Object newElement) { + + if (this.size == this.maxSize) // knows that size starts <= maxSize + System.arraycopy(this.elements, 0, (this.elements = new Object[this.maxSize *= 2]), 0, this.size); + this.elements[this.size++] = newElement; + } + + public void addAll(Object[] newElements) { + + if (this.size + newElements.length >= this.maxSize) { + maxSize = this.size + newElements.length; // assume no more elements will be added + System.arraycopy(this.elements, 0, (this.elements = new Object[this.maxSize]), 0, this.size); + } + System.arraycopy(newElements, 0, this.elements, size, newElements.length); + this.size += newElements.length; + } + + public void addAll(ObjectVector newVector) { + + if (this.size + newVector.size >= this.maxSize) { + maxSize = this.size + newVector.size; // assume no more elements will be added + System.arraycopy(this.elements, 0, (this.elements = new Object[this.maxSize]), 0, this.size); + } + System.arraycopy(newVector.elements, 0, this.elements, size, newVector.size); + this.size += newVector.size; + } + + /** + * Identity check + */ + public boolean containsIdentical(Object element) { + + for (int i = this.size; --i >= 0;) + if (element == this.elements[i]) + return true; + return false; + } + + /** + * Equality check + */ + public boolean contains(Object element) { + + for (int i = this.size; --i >= 0;) + if (element.equals(this.elements[i])) + return true; + return false; + } + + public void copyInto(Object[] targetArray){ + + this.copyInto(targetArray, 0); + } + + public void copyInto(Object[] targetArray, int index){ + + System.arraycopy(this.elements, 0, targetArray, index, this.size); + } + + public Object elementAt(int index) { + + return this.elements[index]; + } + + public Object find(Object element) { + + for (int i = this.size; --i >= 0;) + if (element.equals(this.elements[i])) + return element; + return null; + } + + public Object remove(Object element) { + + // assumes only one occurrence of the element exists + for (int i = this.size; --i >= 0;) + if (element.equals(this.elements[i])) { + // shift the remaining elements down one spot + System.arraycopy(this.elements, i + 1, this.elements, i, --this.size - i); + this.elements[this.size] = null; + return element; + } + return null; + } + + public void removeAll() { + + for (int i = this.size; --i >= 0;) + this.elements[i] = null; + this.size = 0; + } + + public int size(){ + + return this.size; + } + + public String toString() { + + String s = ""; //$NON-NLS-1$ + for (int i = 0; i < this.size; i++) + s += this.elements[i].toString() + "\n"; //$NON-NLS-1$ + return s; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/SimpleNameVector.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/SimpleNameVector.java new file mode 100644 index 0000000..dbf3111 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/SimpleNameVector.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.util; + +public final class SimpleNameVector { + + static int INITIAL_SIZE = 10; + + public int size; + int maxSize; + char[][] elements; + + public SimpleNameVector() { + + this.maxSize = INITIAL_SIZE; + this.size = 0; + this.elements = new char[this.maxSize][]; + } + + public void add(char[] newElement) { + + if (this.size == this.maxSize) // knows that size starts <= maxSize + System.arraycopy(this.elements, 0, (this.elements = new char[this.maxSize *= 2][]), 0, this.size); + this.elements[size++] = newElement; + } + + public void addAll(char[][] newElements) { + + if (this.size + newElements.length >= this.maxSize) { + this.maxSize = this.size + newElements.length; // assume no more elements will be added + System.arraycopy(this.elements, 0, (this.elements = new char[this.maxSize][]), 0, this.size); + } + System.arraycopy(newElements, 0, this.elements, this.size, newElements.length); + this.size += newElements.length; + } + + public void copyInto(Object[] targetArray){ + + System.arraycopy(this.elements, 0, targetArray, 0, this.size); + } + + public boolean contains(char[] element) { + + for (int i = this.size; --i >= 0;) + if (CharOperation.equals(element, this.elements[i])) + return true; + return false; + } + + public char[] elementAt(int index) { + return this.elements[index]; + } + + public char[] remove(char[] element) { + + // assumes only one occurrence of the element exists + for (int i = this.size; --i >= 0;) + if (element == this.elements[i]) { + // shift the remaining elements down one spot + System.arraycopy(this.elements, i + 1, this.elements, i, --this.size - i); + this.elements[this.size] = null; + return element; + } + return null; + } + + public void removeAll() { + + for (int i = this.size; --i >= 0;) + this.elements[i] = null; + this.size = 0; + } + + public int size(){ + + return this.size; + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < this.size; i++) { + buffer.append(this.elements[i]).append("\n"); //$NON-NLS-1$ + } + return buffer.toString(); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/Util.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/Util.java new file mode 100644 index 0000000..ec4ecbb --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/Util.java @@ -0,0 +1,379 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.util; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +public class Util { + + public static String LINE_SEPARATOR = System.getProperty("line.separator"); //$NON-NLS-1$ + public static char[] LINE_SEPARATOR_CHARS = LINE_SEPARATOR.toCharArray(); + public final static char[] SUFFIX_class = ".class".toCharArray(); //$NON-NLS-1$ + public final static char[] SUFFIX_CLASS = ".CLASS".toCharArray(); //$NON-NLS-1$ + public final static char[] SUFFIX_java = ".java".toCharArray(); //$NON-NLS-1$ + public final static char[] SUFFIX_JAVA = ".JAVA".toCharArray(); //$NON-NLS-1$ + public final static char[] SUFFIX_jar = ".jar".toCharArray(); //$NON-NLS-1$ + public final static char[] SUFFIX_JAR = ".JAR".toCharArray(); //$NON-NLS-1$ + public final static char[] SUFFIX_zip = ".zip".toCharArray(); //$NON-NLS-1$ + public final static char[] SUFFIX_ZIP = ".ZIP".toCharArray(); //$NON-NLS-1$ + + private final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$ + private final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$ + + /* Bundle containing messages */ + protected static ResourceBundle bundle; + private final static String bundleName = + "org.eclipse.jdt.internal.compiler.util.messages"; //$NON-NLS-1$ + static { + relocalize(); + } + /** + * Lookup the message with the given ID in this catalog and bind its + * substitution locations with the given strings. + */ + public static String bind(String id, String binding1, String binding2) { + return bind(id, new String[] { binding1, binding2 }); + } + /** + * Lookup the message with the given ID in this catalog and bind its + * substitution locations with the given string. + */ + public static String bind(String id, String binding) { + return bind(id, new String[] { binding }); + } + /** + * Lookup the message with the given ID in this catalog and bind its + * substitution locations with the given string values. + */ + public static String bind(String id, String[] bindings) { + if (id == null) + return "No message available"; //$NON-NLS-1$ + String message = null; + try { + message = bundle.getString(id); + } catch (MissingResourceException e) { + // If we got an exception looking for the message, fail gracefully by just returning + // the id we were looking for. In most cases this is semi-informative so is not too bad. + return "Missing message: " + id + " in: " + bundleName; //$NON-NLS-2$ //$NON-NLS-1$ + } + // for compatibility with MessageFormat which eliminates double quotes in original message + char[] messageWithNoDoubleQuotes = + CharOperation.replace(message.toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE); + message = new String(messageWithNoDoubleQuotes); + + if (bindings == null) + return message; + + int length = message.length(); + int start = -1; + int end = length; + StringBuffer output = new StringBuffer(80); + while (true) { + if ((end = message.indexOf('{', start)) > -1) { + output.append(message.substring(start + 1, end)); + if ((start = message.indexOf('}', end)) > -1) { + int index = -1; + try { + index = Integer.parseInt(message.substring(end + 1, start)); + output.append(bindings[index]); + } catch (NumberFormatException nfe) { + output.append(message.substring(end + 1, start + 1)); + } catch (ArrayIndexOutOfBoundsException e) { + output.append("{missing " + Integer.toString(index) + "}"); //$NON-NLS-2$ //$NON-NLS-1$ + } + } else { + output.append(message.substring(end, length)); + break; + } + } else { + output.append(message.substring(start + 1, length)); + break; + } + } + return output.toString(); + } + /** + * Lookup the message with the given ID in this catalog + */ + public static String bind(String id) { + return bind(id, (String[]) null); + } + /** + * Creates a NLS catalog for the given locale. + */ + public static void relocalize() { + bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault()); + } + /** + * Returns the given bytes as a char array using a given encoding (null means platform default). + */ + public static char[] bytesToChar(byte[] bytes, String encoding) throws IOException { + + return getInputStreamAsCharArray(new ByteArrayInputStream(bytes), bytes.length, encoding); + + } + /** + * Returns the contents of the given file as a byte array. + * @throws IOException if a problem occured reading the file. + */ + public static byte[] getFileByteContent(File file) throws IOException { + InputStream stream = null; + try { + stream = new BufferedInputStream(new FileInputStream(file)); + return getInputStreamAsByteArray(stream, (int) file.length()); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + } + } + } + } + /** + * Returns the contents of the given file as a char array. + * When encoding is null, then the platform default one is used + * @throws IOException if a problem occured reading the file. + */ + public static char[] getFileCharContent(File file, String encoding) throws IOException { + InputStream stream = null; + try { + stream = new BufferedInputStream(new FileInputStream(file)); + return Util.getInputStreamAsCharArray(stream, (int) file.length(), encoding); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + } + } + } + } + /** + * Returns the given input stream's contents as a byte array. + * If a length is specified (ie. if length != -1), only length bytes + * are returned. Otherwise all bytes in the stream are returned. + * Note this doesn't close the stream. + * @throws IOException if a problem occured reading the stream. + */ + public static byte[] getInputStreamAsByteArray(InputStream stream, int length) + throws IOException { + byte[] contents; + if (length == -1) { + contents = new byte[0]; + int contentsLength = 0; + int bytesRead = -1; + do { + int available = stream.available(); + + // resize contents if needed + if (contentsLength + available > contents.length) { + System.arraycopy( + contents, + 0, + contents = new byte[contentsLength + available], + 0, + contentsLength); + } + + // read as many bytes as possible + bytesRead = stream.read(contents, contentsLength, available); + + if (bytesRead > 0) { + // remember length of contents + contentsLength += bytesRead; + } + } while (bytesRead > 0); + + // resize contents if necessary + if (contentsLength < contents.length) { + System.arraycopy( + contents, + 0, + contents = new byte[contentsLength], + 0, + contentsLength); + } + } else { + contents = new byte[length]; + int len = 0; + int readSize = 0; + while ((readSize != -1) && (len != length)) { + // See PR 1FMS89U + // We record first the read size. In this case len is the actual read size. + len += readSize; + readSize = stream.read(contents, len, length - len); + } + } + + return contents; + } + /** + * Returns the given input stream's contents as a character array. + * If a length is specified (ie. if length != -1), only length chars + * are returned. Otherwise all chars in the stream are returned. + * Note this doesn't close the stream. + * @throws IOException if a problem occured reading the stream. + */ + public static char[] getInputStreamAsCharArray(InputStream stream, int length, String encoding) + throws IOException { + InputStreamReader reader = null; + reader = encoding == null + ? new InputStreamReader(stream) + : new InputStreamReader(stream, encoding); + char[] contents; + if (length == -1) { + contents = new char[0]; + int contentsLength = 0; + int charsRead = -1; + do { + int available = stream.available(); + + // resize contents if needed + if (contentsLength + available > contents.length) { + System.arraycopy( + contents, + 0, + contents = new char[contentsLength + available], + 0, + contentsLength); + } + + // read as many chars as possible + charsRead = reader.read(contents, contentsLength, available); + + if (charsRead > 0) { + // remember length of contents + contentsLength += charsRead; + } + } while (charsRead > 0); + + // resize contents if necessary + if (contentsLength < contents.length) { + System.arraycopy( + contents, + 0, + contents = new char[contentsLength], + 0, + contentsLength); + } + } else { + contents = new char[length]; + int len = 0; + int readSize = 0; + while ((readSize != -1) && (len != length)) { + // See PR 1FMS89U + // We record first the read size. In this case len is the actual read size. + len += readSize; + readSize = reader.read(contents, len, length - len); + } + // See PR 1FMS89U + // Now we need to resize in case the default encoding used more than one byte for each + // character + if (len != length) + System.arraycopy(contents, 0, (contents = new char[len]), 0, len); + } + + return contents; + } + + /** + * Returns the contents of the given zip entry as a byte array. + * @throws IOException if a problem occured reading the zip entry. + */ + public static byte[] getZipEntryByteContent(ZipEntry ze, ZipFile zip) + throws IOException { + + InputStream stream = null; + try { + stream = new BufferedInputStream(zip.getInputStream(ze)); + return getInputStreamAsByteArray(stream, (int) ze.getSize()); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + } + } + } + } + /** + * Returns true iff str.toLowerCase().endsWith(".jar") || str.toLowerCase().endsWith(".zip") + * implementation is not creating extra strings. + */ + public final static boolean isArchiveFileName(String name) { + int nameLength = name == null ? 0 : name.length(); + int suffixLength = SUFFIX_JAR.length; + if (nameLength < suffixLength) return false; + + // try to match as JAR file + for (int i = 0; i < suffixLength; i++) { + char c = name.charAt(nameLength - i - 1); + int suffixIndex = suffixLength - i - 1; + if (c != SUFFIX_jar[suffixIndex] && c != SUFFIX_JAR[suffixIndex]) { + + // try to match as ZIP file + suffixLength = SUFFIX_ZIP.length; + if (nameLength < suffixLength) return false; + for (int j = 0; j < suffixLength; j++) { + c = name.charAt(nameLength - j - 1); + suffixIndex = suffixLength - j - 1; + if (c != SUFFIX_zip[suffixIndex] && c != SUFFIX_ZIP[suffixIndex]) return false; + } + return true; + } + } + return true; + } + /** + * Returns true iff str.toLowerCase().endsWith(".class") + * implementation is not creating extra strings. + */ + public final static boolean isClassFileName(String name) { + int nameLength = name == null ? 0 : name.length(); + int suffixLength = SUFFIX_CLASS.length; + if (nameLength < suffixLength) return false; + + for (int i = 0; i < suffixLength; i++) { + char c = name.charAt(nameLength - i - 1); + int suffixIndex = suffixLength - i - 1; + if (c != SUFFIX_class[suffixIndex] && c != SUFFIX_CLASS[suffixIndex]) return false; + } + return true; + } + /** + * Returns true iff str.toLowerCase().endsWith(".java") + * implementation is not creating extra strings. + */ + public final static boolean isJavaFileName(String name) { + int nameLength = name == null ? 0 : name.length(); + int suffixLength = SUFFIX_JAVA.length; + if (nameLength < suffixLength) return false; + + for (int i = 0; i < suffixLength; i++) { + char c = name.charAt(nameLength - i - 1); + int suffixIndex = suffixLength - i - 1; + if (c != SUFFIX_java[suffixIndex] && c != SUFFIX_JAVA[suffixIndex]) return false; + } + return true; + } +} \ No newline at end of file