blob: 9bfb89dd4ce7c8227d3acf1e170886fca9558ecf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.debug.eval.ast.engine;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration;
import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration;
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
import org.eclipse.jdt.core.dom.ArrayAccess;
import org.eclipse.jdt.core.dom.ArrayCreation;
import org.eclipse.jdt.core.dom.ArrayInitializer;
import org.eclipse.jdt.core.dom.ArrayType;
import org.eclipse.jdt.core.dom.AssertStatement;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.BlockComment;
import org.eclipse.jdt.core.dom.BooleanLiteral;
import org.eclipse.jdt.core.dom.BreakStatement;
import org.eclipse.jdt.core.dom.CastExpression;
import org.eclipse.jdt.core.dom.CatchClause;
import org.eclipse.jdt.core.dom.CharacterLiteral;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ConditionalExpression;
import org.eclipse.jdt.core.dom.ConstructorInvocation;
import org.eclipse.jdt.core.dom.ContinueStatement;
import org.eclipse.jdt.core.dom.DoStatement;
import org.eclipse.jdt.core.dom.EmptyStatement;
import org.eclipse.jdt.core.dom.EnhancedForStatement;
import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
import org.eclipse.jdt.core.dom.EnumDeclaration;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.FieldAccess;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.ForStatement;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.IPackageBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.IfStatement;
import org.eclipse.jdt.core.dom.ImportDeclaration;
import org.eclipse.jdt.core.dom.InfixExpression;
import org.eclipse.jdt.core.dom.Initializer;
import org.eclipse.jdt.core.dom.InstanceofExpression;
import org.eclipse.jdt.core.dom.Javadoc;
import org.eclipse.jdt.core.dom.LabeledStatement;
import org.eclipse.jdt.core.dom.LineComment;
import org.eclipse.jdt.core.dom.MarkerAnnotation;
import org.eclipse.jdt.core.dom.MemberRef;
import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.MethodRef;
import org.eclipse.jdt.core.dom.MethodRefParameter;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.NullLiteral;
import org.eclipse.jdt.core.dom.NumberLiteral;
import org.eclipse.jdt.core.dom.PackageDeclaration;
import org.eclipse.jdt.core.dom.ParameterizedType;
import org.eclipse.jdt.core.dom.ParenthesizedExpression;
import org.eclipse.jdt.core.dom.PostfixExpression;
import org.eclipse.jdt.core.dom.PrefixExpression;
import org.eclipse.jdt.core.dom.PrimitiveType;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.QualifiedType;
import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
import org.eclipse.jdt.core.dom.SuperFieldAccess;
import org.eclipse.jdt.core.dom.SuperMethodInvocation;
import org.eclipse.jdt.core.dom.SwitchCase;
import org.eclipse.jdt.core.dom.SwitchStatement;
import org.eclipse.jdt.core.dom.SynchronizedStatement;
import org.eclipse.jdt.core.dom.TagElement;
import org.eclipse.jdt.core.dom.TextElement;
import org.eclipse.jdt.core.dom.ThisExpression;
import org.eclipse.jdt.core.dom.ThrowStatement;
import org.eclipse.jdt.core.dom.TryStatement;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclarationStatement;
import org.eclipse.jdt.core.dom.TypeLiteral;
import org.eclipse.jdt.core.dom.TypeParameter;
import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
import org.eclipse.jdt.core.dom.WhileStatement;
import org.eclipse.jdt.core.dom.WildcardType;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.AndAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.AndOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.ArrayAllocation;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.ArrayInitializerInstruction;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.AssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.Cast;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.CompoundInstruction;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.ConditionalJump;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.Constructor;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.DivideAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.DivideOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.Dup;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.DupX1;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.EqualEqualOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.GreaterEqualOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.GreaterOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.InstanceOfOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.Instruction;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.InstructionSequence;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.Jump;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.LeftShiftAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.LeftShiftOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.LessEqualOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.LessOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.LocalVariableCreation;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.MinusAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.MinusOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.MultiplyAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.MultiplyOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.NoOp;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.NotOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.OrAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.OrOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PlusAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PlusOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.Pop;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PostfixMinusMinusOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PostfixPlusPlusOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PrefixMinusMinusOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PrefixPlusPlusOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushArrayLength;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushArrayType;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushBoolean;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushChar;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushClassLiteralValue;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushDouble;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushFieldVariable;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushFloat;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushInt;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushLocalVariable;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushLong;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushNull;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushPrimitiveType;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushStaticFieldVariable;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushString;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushThis;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushType;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.RemainderAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.RemainderOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.ReturnInstruction;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.RightShiftAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.RightShiftOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.SendMessage;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.SendStaticMessage;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.ThrowInstruction;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.TwiddleOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.UnaryMinusOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.UnaryPlusOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.UnsignedRightShiftAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.UnsignedRightShiftOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.Value;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.XorAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.XorOperator;
import com.ibm.icu.text.MessageFormat;
/**
* The AST instruction compiler generates a sequence
* of instructions (InstructionSequence) from a
* DOM AST.
*/
public class ASTInstructionCompiler extends ASTVisitor {
/**
* Represent a break or a continue instruction.
* These instructions needs are stored and managed later by their
* related statement.
*/
class CompleteInstruction {
Jump fInstruction;
String fLabel;
boolean fIsBreak;
public CompleteInstruction(Jump instruction, String label, boolean isBreak) {
fInstruction= instruction;
fLabel= label;
fIsBreak= isBreak;
}
}
/**
* Whether to print debug messages to the console
*/
private static boolean VERBOSE = false;
private InstructionSequence fInstructions;
/**
* The list of pending break and continue instruction.
*/
private List fCompleteInstructions;
private int fStartPosition;
private boolean fActive;
private boolean fHasErrors;
private Stack fStack;
private int fCounter;
// internal index used to create unique variable name
private int fUniqueIdIndex= 0;
/**
* Create a new AST instruction compiler
*/
public ASTInstructionCompiler(int startPosition, String snippet) {
fStartPosition = startPosition;
fInstructions = new InstructionSequence(snippet);
fStack = new Stack();
fCompleteInstructions= new ArrayList();
}
/**
* Returns the instruction sequence generated
* by this AST instruction compiler
*/
public InstructionSequence getInstructions() {
return fInstructions;
}
/**
* Returns whether the generated instruction sequence
* has errors.
* Errors include:
* <ol>
* <li>AST contains unimplemented operations (features which will be supported,
* but aren't yet)</li>
* <li>AST contains unsupported operations (features which are not yet implemented
* and are likely NOT to be implemented)</li>
* </ol>
*/
public boolean hasErrors() {
return fHasErrors;
}
private void setHasError(boolean value) {
fHasErrors= value;
}
private void addErrorMessage(String message) {
fInstructions.addError(message);
}
private boolean isActive() {
return fActive;
}
private void setActive(boolean active) {
fActive = active;
}
private void push(Instruction i) {
fStack.push(i);
}
private Instruction pop() {
return (Instruction)fStack.pop();
}
private void storeInstruction() {
Instruction instruction= pop();
fCounter++;
if (instruction instanceof CompoundInstruction) {
((CompoundInstruction)instruction).setEnd(fCounter);
}
fInstructions.add(instruction);
verbose("Add " + instruction.toString()); //$NON-NLS-1$
}
/**
* Prints the given message to the console if verbose
* mode is on.
*
* @param message the message to display
*/
private void verbose(String message) {
if (VERBOSE) {
System.out.println(message);
}
}
private String getTypeName(ITypeBinding typeBinding) {
if (typeBinding.isRawType()) {
typeBinding= typeBinding.getErasure();
}
if (typeBinding.isTypeVariable()) {
ITypeBinding[] typeBounds= typeBinding.getTypeBounds();
if (typeBounds.length > 0) {
String name= getTypeName(typeBounds[0]);
if (typeBounds.length > 1 && "java.lang.Object".equals(name)) { //$NON-NLS-1$
return getTypeName(typeBounds[1]);
}
return name;
}
return "java.lang.Object"; //$NON-NLS-1$
}
StringBuffer name;
if (typeBinding.isArray()) {
name= new StringBuffer(getTypeName(typeBinding.getElementType()));
int dimensions= typeBinding.getDimensions();
for (int i= 0; i < dimensions; i++) {
name.append("[]"); //$NON-NLS-1$
}
return name.toString();
}
String typeName= typeBinding.getName();
int parameters= typeName.indexOf('<');
if (parameters >= 0) {
typeName= typeName.substring(0, parameters);
}
name= new StringBuffer(typeName);
IPackageBinding packageBinding= typeBinding.getPackage();
typeBinding= typeBinding.getDeclaringClass();
while(typeBinding != null) {
name.insert(0, '$').insert(0, typeBinding.getName());
typeBinding= typeBinding.getDeclaringClass();
}
if (packageBinding != null && !packageBinding.isUnnamed()) {
name.insert(0, '.').insert(0, packageBinding.getName());
}
return name.toString();
}
private String getTypeSignature(ITypeBinding typeBinding) {
return Signature.createTypeSignature(getTypeName(typeBinding), true).replace('.', '/');
}
private boolean isALocalType(ITypeBinding typeBinding) {
while(typeBinding != null) {
if (typeBinding.isLocal()) {
return true;
}
typeBinding= typeBinding.getDeclaringClass();
}
return false;
}
private boolean containsALocalType(IMethodBinding methodBinding) {
ITypeBinding[] typeBindings= methodBinding.getParameterTypes();
for (int i= 0, length= typeBindings.length; i < length; i++) {
if (isALocalType(typeBindings[i])) {
return true;
}
}
return false;
}
private int getEnclosingLevel(ASTNode node, ITypeBinding referenceTypeBinding) {
ASTNode parent = node;
ITypeBinding refbinding = referenceTypeBinding.isParameterizedType() ? referenceTypeBinding.getTypeDeclaration() : referenceTypeBinding;
do {
parent = parent.getParent();
} while (parent != null && !(parent instanceof AbstractTypeDeclaration || parent instanceof AnonymousClassDeclaration));
if(parent == null) {
return 0;
}
ITypeBinding parentBinding = null;
if(parent instanceof AbstractTypeDeclaration) {
parentBinding = ((AbstractTypeDeclaration)parent).resolveBinding();
}
else if(parent instanceof AnonymousClassDeclaration) {
parentBinding = ((AnonymousClassDeclaration)parent).resolveBinding();
}
if (parentBinding != null && (parentBinding.isEqualTo(refbinding) || parentBinding.isCastCompatible(refbinding))) {
return 0;
}
return getEnclosingLevel(parent, referenceTypeBinding) + 1;
}
private int getSuperLevel(ITypeBinding current, ITypeBinding reference) {
if (current.equals(reference)) {
return 0;
}
return getSuperLevel(current.getSuperclass(), reference);
}
/**
* Return the label associated with the given statement.
*
* @param statement the statement.
* @return the associated label, or <code>null</code> if there is none.
*/
private String getLabel(Statement statement) {
ASTNode parent= statement.getParent();
if (parent instanceof LabeledStatement) {
return ((LabeledStatement)parent).getLabel().getIdentifier();
}
return null;
}
/**
* Append a pop instruction in the instruction list if needed.
* A pop instruction is added when the expression has a return value,
* i.e. all expressions expect method invocation expressions which
* have <code>void</code> as return type and variable declaration expression.
*
* @param expression the expression to test.
*/
private void addPopInstructionIfNeeded(Expression expression) {
boolean pop= true;
if (expression instanceof MethodInvocation) {
IMethodBinding methodBinding= (IMethodBinding)((MethodInvocation)expression).getName().resolveBinding();
if (methodBinding != null && "void".equals(methodBinding.getReturnType().getName())) { //$NON-NLS-1$
pop= false;
}
} else if (expression instanceof SuperMethodInvocation) {
IMethodBinding methodBinding= (IMethodBinding)((SuperMethodInvocation)expression).getName().resolveBinding();
if (methodBinding != null && "void".equals(methodBinding.getReturnType().getName())) { //$NON-NLS-1$
pop= false;
}
} else if (expression instanceof VariableDeclarationExpression) {
pop= false;
}
if (pop) {
addPopInstruction();
}
}
/**
*
*/
private void addPopInstruction() {
Instruction lastInstruction= fInstructions.getInstruction(fInstructions.getEnd());
push(new Pop(lastInstruction.getSize() + 1));
storeInstruction();
}
/**
* Check the current type of a value and the requested type to decide if boxing/un-boxing is required.
* If needed, the correct instruction is added to the stack
* Returns true if a storeInstruction() is needed after visiting the expression
*/
private boolean checkAutoBoxing(ITypeBinding valueBinding, ITypeBinding requestedBinding) {
if (valueBinding == null) {
return false; // unresolved
}
if (valueBinding.isPrimitive() == requestedBinding.isPrimitive()) {
return false;
}
if (requestedBinding.isPrimitive()) {
unBoxing(valueBinding);
} else {
boxing(requestedBinding, valueBinding);
}
return true;
}
/**
* Add to the stack the instruction to box a primitive value.
*/
private void boxing(ITypeBinding requestedBinding, ITypeBinding valueBinding) {
String requestedTypeName= requestedBinding.getQualifiedName();
if ("java.lang.Object".equals(requestedTypeName)) { //$NON-NLS-1$
switch (valueBinding.getBinaryName().charAt(0)) {
case 'I':
push(new SendStaticMessage("java.lang.Integer", "valueOf", "(I)Ljava/lang/Integer;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
break;
case 'C':
push(new SendStaticMessage("java.lang.Character", "valueOf", "(C)Ljava/lang/Character;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
break;
case 'B':
push(new SendStaticMessage("java.lang.Byte", "valueOf", "(B)Ljava/lang/Byte;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
break;
case 'S':
push(new SendStaticMessage("java.lang.Short", "valueOf", "(S)Ljava/lang/Short;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
break;
case 'J':
push(new SendStaticMessage("java.lang.Long", "valueOf", "(J)Ljava/lang/Long;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
break;
case 'F':
push(new SendStaticMessage("java.lang.Float", "valueOf", "(F)Ljava/lang/Float;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
break;
case 'D':
push(new SendStaticMessage("java.lang.Double", "valueOf", "(D)Ljava/lang/Double;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
break;
case 'Z':
push(new SendStaticMessage("java.lang.Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
break;
}
} else if ("java.lang.Integer".equals(requestedTypeName)) { //$NON-NLS-1$
push(new SendStaticMessage(requestedTypeName, "valueOf", "(I)Ljava/lang/Integer;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Character".equals(requestedTypeName)) { //$NON-NLS-1$
push(new SendStaticMessage(requestedTypeName, "valueOf", "(C)Ljava/lang/Character;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Byte".equals(requestedTypeName)) { //$NON-NLS-1$
push(new SendStaticMessage(requestedTypeName, "valueOf", "(B)Ljava/lang/Byte;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Short".equals(requestedTypeName)) { //$NON-NLS-1$
push(new SendStaticMessage(requestedTypeName, "valueOf", "(S)Ljava/lang/Short;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Long".equals(requestedTypeName)) { //$NON-NLS-1$
push(new SendStaticMessage(requestedTypeName, "valueOf", "(J)Ljava/lang/Long;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Float".equals(requestedTypeName)) { //$NON-NLS-1$
push(new SendStaticMessage(requestedTypeName, "valueOf", "(F)Ljava/lang/Float;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Double".equals(requestedTypeName)) { //$NON-NLS-1$
push(new SendStaticMessage(requestedTypeName, "valueOf", "(D)Ljava/lang/Double;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Boolean".equals(requestedTypeName)) { //$NON-NLS-1$
push(new SendStaticMessage(requestedTypeName, "valueOf", "(Z)Ljava/lang/Boolean;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
}
}
/**
* Add the instruction to un-box a non-primitive value if needed.
* Returns true if a storeInstruction() is needed after visiting the expression
*/
private boolean unBoxing(ITypeBinding valueBinding) {
String valueTypeName= valueBinding.getQualifiedName();
if ("java.lang.Integer".equals(valueTypeName)) { //$NON-NLS-1$
push(new SendMessage("intValue", "()I", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Character".equals(valueTypeName)) { //$NON-NLS-1$
push(new SendMessage("charValue", "()C", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Byte".equals(valueTypeName)) { //$NON-NLS-1$
push(new SendMessage("byteValue", "()B", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Short".equals(valueTypeName)) { //$NON-NLS-1$
push(new SendMessage("shortValue", "()S", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Long".equals(valueTypeName)) { //$NON-NLS-1$
push(new SendMessage("longValue", "()J", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Float".equals(valueTypeName)) { //$NON-NLS-1$
push(new SendMessage("floatValue", "()F", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Double".equals(valueTypeName)) { //$NON-NLS-1$
push(new SendMessage("doubleValue", "()D", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Boolean".equals(valueTypeName)) { //$NON-NLS-1$
push(new SendMessage("booleanValue", "()Z", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else {
return false;
}
return true;
}
/**
* End visit methods
*
* There are two paths to ending a visit to a node:
* <ol>
* <li>For control statements, the necessary control
* instructions (jump, conditional jump) are inserted
* into the instruction sequence</li>
* <li>For other cases, we simply remove the node's
* instruction from the stack and add it to the
* instruction sequence.</li>
* </ol>
*/
/**
* @see ASTVisitor#endVisit(AnonymousClassDeclaration)
*/
public void endVisit(AnonymousClassDeclaration node) {
}
/**
* @see ASTVisitor#endVisit(ArrayAccess)
*/
public void endVisit(ArrayAccess node) {
if (!isActive() || hasErrors())
return;
ITypeBinding typeBinding = node.getIndex().resolveTypeBinding();
if (typeBinding != null && unBoxing(typeBinding)) {
// un-box the index, if required
storeInstruction();
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ArrayCreation)
*/
public void endVisit(ArrayCreation node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ArrayInitializer)
*/
public void endVisit(ArrayInitializer node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ArrayType)
*/
public void endVisit(ArrayType node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(AssertStatement)
*/
public void endVisit(AssertStatement node) {
}
/**
* @see ASTVisitor#endVisit(Assignment)
*/
public void endVisit(Assignment node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(Block)
*/
public void endVisit(Block node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(BooleanLiteral)
*/
public void endVisit(BooleanLiteral node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(BreakStatement)
*/
public void endVisit(BreakStatement node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(CastExpression)
*/
public void endVisit(CastExpression node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(CatchClause)
*/
public void endVisit(CatchClause node) {
}
/**
* @see ASTVisitor#endVisit(CharacterLiteral)
*/
public void endVisit(CharacterLiteral node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ClassInstanceCreation)
*/
public void endVisit(ClassInstanceCreation node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(CompilationUnit)
*/
public void endVisit(CompilationUnit node) {
}
/**
* @see ASTVisitor#endVisit(ConditionalExpression)
*/
public void endVisit(ConditionalExpression node) {
if (!isActive() || hasErrors())
return;
// Get the instructions
int ifFalseAddress= fInstructions.getEnd();
Instruction ifFalse= fInstructions.get(ifFalseAddress);
int ifTrueAddress= ifFalseAddress - ifFalse.getSize();
Instruction ifTrue= fInstructions.get(ifTrueAddress);
int conditionalAddress= ifTrueAddress - ifTrue.getSize();
// Insert the conditional jump
ConditionalJump conditionalJump= new ConditionalJump(false);
fInstructions.insert(conditionalJump, conditionalAddress + 1);
// Insert the jump
int jumpAddress= ifTrueAddress + 2;
Jump jump= new Jump();
fInstructions.insert(jump, jumpAddress);
// Set the jump offsets
conditionalJump.setOffset(ifTrue.getSize() + 1);
jump.setOffset(ifFalse.getSize() + 1);
fCounter += 2;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ConstructorInvocation)
*/
public void endVisit(ConstructorInvocation node) {
}
/**
* @see ASTVisitor#endVisit(ContinueStatement)
*/
public void endVisit(ContinueStatement node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(DoStatement)
*/
public void endVisit(DoStatement node) {
if (!isActive() || hasErrors())
return;
/* The structure of generated instructions is :
*
* --
* | body
* --
* --
* |condition
* --
* - jump to the first instruction of the body if the condition is true.
*
*/
String label= getLabel(node);
// get address of each part
int conditionAddress= fInstructions.getEnd();
Instruction condition= fInstructions.getInstruction(conditionAddress);
int bodyAddress= conditionAddress - condition.getSize();
Instruction body= fInstructions.getInstruction(bodyAddress);
int bodyStartAddress= bodyAddress - body.getSize();
// add the conditionnalJump
ConditionalJump conditionalJump= new ConditionalJump(true);
fInstructions.add(conditionalJump);
fCounter++;
// set jump offsets
conditionalJump.setOffset(-(condition.getSize() + body.getSize() + 1));
// for each pending break or continue instruction which are related to
// this loop, set the offset of the corresponding jump.
for (Iterator iter= fCompleteInstructions.iterator(); iter.hasNext();) {
CompleteInstruction instruction= (CompleteInstruction) iter.next();
Jump jumpInstruction= instruction.fInstruction;
int instructionAddress= fInstructions.indexOf(jumpInstruction);
if (instructionAddress > bodyStartAddress && (instruction.fLabel == null || instruction.fLabel.equals(label))) {
iter.remove();
if (instruction.fIsBreak) {
// jump to the instruction after the last jump
jumpInstruction.setOffset((conditionAddress - instructionAddress) + 1);
} else {
// jump to the first instruction of the condition
jumpInstruction.setOffset(bodyAddress - instructionAddress);
}
}
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(EmptyStatement)
*/
public void endVisit(EmptyStatement node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#endVisit(org.eclipse.jdt.core.dom.EnhancedForStatement)
*/
public void endVisit(EnhancedForStatement node) {
if (!isActive() || hasErrors())
return;
/* The structure of generated instructions is :
*
* For an array:
* --
* | <ParameterType>[] a= Expression
* | int i= 0
* | <ParameterType> <ParameterName>
* --
* --
* | i < a.length
* - jump to the instruction after the last jump if the condition is false.
* --
* --
* | s= a[i]
* | Body
* --
* --
* - jump to the first instruction of the condition.
*
* For an Iterable:
* --
* | Iterator i= Expression.iterator()
* | <ParameterType> <ParameterName>
* --
* --
* | i.hasNext()
* - jump to the instruction after the last jump if the condition is false.
* --
* --
* | s= i.next()
* | Body
* --
* --
* - jump to the first instruction of the condition.
*
*/
int bodyAddress= fInstructions.getEnd();
Instruction body= fInstructions.getInstruction(bodyAddress);
int conditionAddress= bodyAddress - body.getSize();
Instruction condition= fInstructions.getInstruction(conditionAddress);
int initAddress= conditionAddress - condition.getSize();
// add conditional jump
ConditionalJump condJump= new ConditionalJump(false);
fInstructions.insert(condJump, conditionAddress + 1);
bodyAddress++;
fCounter++;
condJump.setOffset(body.getSize() + 1);
// add jump
Jump jump= new Jump();
fInstructions.add(jump);
fCounter++;
jump.setOffset(initAddress - (bodyAddress + 1));
// for each pending break or continue instruction which are related to
// this loop, set the offset of the corresponding jump.
String label= getLabel(node);
for (Iterator iter= fCompleteInstructions.iterator(); iter.hasNext();) {
CompleteInstruction instruction= (CompleteInstruction) iter.next();
Jump jumpInstruction= instruction.fInstruction;
int instructionAddress= fInstructions.indexOf(jumpInstruction);
if (instructionAddress > conditionAddress && (instruction.fLabel == null || instruction.fLabel.equals(label))) {
iter.remove();
if (instruction.fIsBreak) {
// jump to the instruction after the last jump
jumpInstruction.setOffset((bodyAddress - instructionAddress) + 1);
} else {
// jump to the first instruction of the condition
jumpInstruction.setOffset(initAddress - instructionAddress);
}
}
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ExpressionStatement)
*/
public void endVisit(ExpressionStatement node) {
if (!isActive() || hasErrors())
return;
addPopInstructionIfNeeded(node.getExpression());
}
/**
* @see ASTVisitor#endVisit(FieldAccess)
*/
public void endVisit(FieldAccess node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(FieldDeclaration)
*/
public void endVisit(FieldDeclaration node) {
}
/**
* @see ASTVisitor#endVisit(ForStatement)
*/
public void endVisit(ForStatement node) {
if (!isActive() || hasErrors())
return;
/* The structure of generated instructions is :
*
* --
* |initialization
* --
* --
* |condition
* --
* - jump to the instruction after the last jump if the condition is false.
* --
* | body
* --
* --
* | updaters
* --
* - jump to the first instruction of the condition.
*
*/
String label= getLabel(node);
boolean hasCondition= node.getExpression() != null;
// get address of each part
int updatersAddress= fInstructions.getEnd();
Instruction updaters= fInstructions.getInstruction(updatersAddress);
int bodyAddress= updatersAddress - updaters.getSize();
Instruction body= fInstructions.getInstruction(bodyAddress);
int bodyStartAddress= bodyAddress - body.getSize();
int conditionAddress;
Instruction condition;
if (hasCondition) {
conditionAddress= bodyStartAddress;
condition= fInstructions.getInstruction(conditionAddress);
} else {
conditionAddress= 0;
condition= null;
}
// add jump
Jump jump= new Jump();
fInstructions.add(jump);
fCounter++;
if (hasCondition) {
// add conditional jump
ConditionalJump condJump= new ConditionalJump(false);
fInstructions.insert(condJump, conditionAddress + 1);
bodyAddress++;
bodyStartAddress++;
updatersAddress++;
fCounter++;
// set conditional jump offset
condJump.setOffset(body.getSize() + updaters.getSize() + 1);
}
// set jump offset
jump.setOffset(-((hasCondition && (condition != null) ? condition.getSize() : 0) + body.getSize() + updaters.getSize() + 2));
// for each pending break or continue instruction which are related to
// this loop, set the offset of the corresponding jump.
for (Iterator iter= fCompleteInstructions.iterator(); iter.hasNext();) {
CompleteInstruction instruction= (CompleteInstruction) iter.next();
Jump jumpInstruction= instruction.fInstruction;
int instructionAddress= fInstructions.indexOf(jumpInstruction);
if (instructionAddress > bodyStartAddress && (instruction.fLabel == null || instruction.fLabel.equals(label))) {
iter.remove();
if (instruction.fIsBreak) {
// jump to the instruction after the last jump
jumpInstruction.setOffset((updatersAddress - instructionAddress) + 1);
} else {
// jump to the first instruction of the condition
jumpInstruction.setOffset(bodyAddress - instructionAddress);
}
}
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(IfStatement)
*/
public void endVisit(IfStatement node) {
if (!isActive() || hasErrors())
return;
boolean hasElseStatement= node.getElseStatement() != null;
// Get the instructions
int ifFalseAddress= 0;
Instruction ifFalse= null;
int ifTrueAddress= 0;
Instruction ifTrue= null;
if (hasElseStatement) {
ifFalseAddress= fInstructions.getEnd();
ifFalse= fInstructions.get(ifFalseAddress);
ifTrueAddress= ifFalseAddress - ifFalse.getSize();
ifTrue= fInstructions.get(ifTrueAddress);
} else {
ifTrueAddress= fInstructions.getEnd();
ifTrue= fInstructions.get(ifTrueAddress);
}
int conditionalAddress= ifTrueAddress - ifTrue.getSize();
// Insert the conditional jump
ConditionalJump conditionalJump= new ConditionalJump(false);
fInstructions.insert(conditionalJump, conditionalAddress + 1);
// Set the jump offset
conditionalJump.setOffset(ifTrue.getSize() + ((hasElseStatement)? 1 : 0));
fCounter++;
if (hasElseStatement) {
// Insert the jump
int jumpAddress= ifTrueAddress + 2;
Jump jump= new Jump();
fInstructions.insert(jump, jumpAddress);
// Set the jump offset
jump.setOffset(ifFalse.getSize() + 1);
fCounter++;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ImportDeclaration)
*/
public void endVisit(ImportDeclaration node) {
}
/**
* @see ASTVisitor#endVisit(InfixExpression)
*/
public void endVisit(InfixExpression node) {
}
/**
* @see ASTVisitor#endVisit(Initializer)
*/
public void endVisit(Initializer node) {
}
/**
* @see ASTVisitor#endVisit(InstanceofExpression)
*/
public void endVisit(InstanceofExpression node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(Javadoc)
*/
public void endVisit(Javadoc node) {
}
/**
* @see ASTVisitor#endVisit(LabeledStatement)
*/
public void endVisit(LabeledStatement node) {
if (!isActive() || hasErrors())
return;
String label= node.getLabel().getIdentifier();
// for each pending continue instruction which are related to
// this statement, set the offset of the corresponding jump.
for (Iterator iter= fCompleteInstructions.iterator(); iter.hasNext();) {
CompleteInstruction instruction= (CompleteInstruction) iter.next();
if (instruction.fLabel != null && instruction.fLabel.equals(label)) {
iter.remove();
Jump jumpInstruction= instruction.fInstruction;
int instructionAddress= fInstructions.indexOf(jumpInstruction);
if (instruction.fIsBreak) {
// jump to the instruction after the statement
jumpInstruction.setOffset(fInstructions.getEnd() - instructionAddress);
}
}
}
}
/**
* @see ASTVisitor#endVisit(MethodDeclaration)
*/
public void endVisit(MethodDeclaration node) {
setActive(false);
}
/**
* @see ASTVisitor#endVisit(MethodInvocation)
*/
public void endVisit(MethodInvocation node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(NullLiteral)
*/
public void endVisit(NullLiteral node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(NumberLiteral)
*/
public void endVisit(NumberLiteral node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(PackageDeclaration)
*/
public void endVisit(PackageDeclaration node) {
}
/**
* @see ASTVisitor#endVisit(SimpleType)
*/
public void endVisit(ParameterizedType node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ParenthesizedExpression)
*/
public void endVisit(ParenthesizedExpression node) {
}
/**
* @see ASTVisitor#endVisit(PostfixExpression)
*/
public void endVisit(PostfixExpression node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(PrefixExpression)
*/
public void endVisit(PrefixExpression node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(PrimitiveType)
*/
public void endVisit(PrimitiveType node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(QualifiedName)
*/
public void endVisit(QualifiedName node) {
}
/**
* @see ASTVisitor#endVisit(SimpleType)
*/
public void endVisit(QualifiedType node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ReturnStatement)
*/
public void endVisit(ReturnStatement node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(SimpleName)
*/
public void endVisit(SimpleName node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(SimpleType)
*/
public void endVisit(SimpleType node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(SingleVariableDeclaration)
*/
public void endVisit(SingleVariableDeclaration node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(StringLiteral)
*/
public void endVisit(StringLiteral node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(SuperConstructorInvocation)
*/
public void endVisit(SuperConstructorInvocation node) {
}
/**
* @see ASTVisitor#endVisit(SuperFieldAccess)
*/
public void endVisit(SuperFieldAccess node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(SuperMethodInvocation)
*/
public void endVisit(SuperMethodInvocation node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(SwitchCase)
*/
public void endVisit(SwitchCase node) {
// never called
}
/**
* @see ASTVisitor#endVisit(SwitchStatement)
*/
public void endVisit(SwitchStatement node) {
// nothing to do
}
/**
* @see ASTVisitor#endVisit(SynchronizedStatement)
*/
public void endVisit(SynchronizedStatement node) {
}
/**
* @see ASTVisitor#endVisit(ThisExpression)
*/
public void endVisit(ThisExpression node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ThrowStatement)
*/
public void endVisit(ThrowStatement node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(TryStatement)
*/
public void endVisit(TryStatement node) {
}
/**
* @see ASTVisitor#endVisit(TypeDeclaration)
*/
public void endVisit(TypeDeclaration node) {
}
/**
* @see ASTVisitor#endVisit(TypeDeclarationStatement)
*/
public void endVisit(TypeDeclarationStatement node) {
}
/**
* @see ASTVisitor#endVisit(TypeLiteral)
*/
public void endVisit(TypeLiteral node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(VariableDeclarationExpression)
*/
public void endVisit(VariableDeclarationExpression node) {
}
/**
* @see ASTVisitor#endVisit(VariableDeclarationFragment)
*/
public void endVisit(VariableDeclarationFragment node) {
if (!isActive() || hasErrors())
return;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(VariableDeclarationStatement)
*/
public void endVisit(VariableDeclarationStatement node) {
}
/**
* @see ASTVisitor#endVisit(WhileStatement)
*/
public void endVisit(WhileStatement node) {
if (!isActive() || hasErrors())
return;
/* The structure of generated instructions is :
*
* --
* |condition
* --
* - jump to the instruction after the last jump if the condition is false.
* --
* | body
* --
* - jump to the first instruction of the condition.
*
*/
String label= getLabel(node);
// get address of each part
int bodyAddress= fInstructions.getEnd();
Instruction body= fInstructions.getInstruction(bodyAddress);
int conditionAddress= bodyAddress - body.getSize();
Instruction condition= fInstructions.getInstruction(conditionAddress);
// add the conditionnalJump
ConditionalJump conditionalJump= new ConditionalJump(false);
fInstructions.insert(conditionalJump, conditionAddress + 1);
// add the jump
Jump jump= new Jump();
fInstructions.add(jump);
// set jump offsets
conditionalJump.setOffset(body.getSize() + 1);
jump.setOffset(-(condition.getSize() + body.getSize() + 2));
// for each pending break or continue instruction which are related to
// this loop, set the offset of the corresponding jump.
for (Iterator iter= fCompleteInstructions.iterator(); iter.hasNext();) {
CompleteInstruction instruction= (CompleteInstruction) iter.next();
Jump jumpInstruction= instruction.fInstruction;
int instructionAddress= fInstructions.indexOf(jumpInstruction);
if (instructionAddress > conditionAddress && (instruction.fLabel == null || instruction.fLabel.equals(label))) {
iter.remove();
if (instruction.fIsBreak) {
// jump to the instruction after the last jump
jumpInstruction.setOffset((bodyAddress - instructionAddress) + 2);
} else {
// jump to the first instruction of the condition
jumpInstruction.setOffset((conditionAddress - condition.getSize()) - instructionAddress);
}
}
}
fCounter+= 2;
storeInstruction();
}
/*
* Visit methods
*
* There are two variations of node visiting:
* <ol>
* <li>Push the instruction corresponding to the node
* onto the stack and return <code>true</code> to visit
* the children of the node.</li>
* <li>Push the instruction corresponding to the node
* onto the stack and visit the children of the node
* manually (return <code>false</code> to avoid the
* default child visiting implementation).</li>
* </ol>
*/
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.AnnotationTypeDeclaration)
*/
public boolean visit(AnnotationTypeDeclaration node) {
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration)
*/
public boolean visit(AnnotationTypeMemberDeclaration node) {
return false;
}
/**
* @see ASTVisitor#visit(AnonymousClassDeclaration)
*/
public boolean visit(AnonymousClassDeclaration node) {
if (!isActive()) {
return true;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Anonymous_type_declaration_cannot_be_used_in_an_evaluation_expression_2);
return false;
}
/**
* @see ASTVisitor#visit(ArrayAccess)
*/
public boolean visit(ArrayAccess node) {
if (!isActive()) {
return false;
}
push(new org.eclipse.jdt.internal.debug.eval.ast.instructions.ArrayAccess(fCounter));
return true;
}
/**
* @see ASTVisitor#visit(ArrayCreation)
*/
public boolean visit(ArrayCreation node) {
if (!isActive()) {
return false;
}
ArrayType arrayType= node.getType();
ITypeBinding binding = resolveTypeBinding(arrayType);
if (binding != null && isALocalType(binding.getElementType())) {
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Local_type_array_instance_creation_cannot_be_used_in_an_evaluation_expression_29);
setHasError(true);
return false;
}
push(new ArrayAllocation(arrayType.getDimensions(), node.dimensions().size(), node.getInitializer() != null, fCounter));
return true;
}
/**
* @see ASTVisitor#visit(ArrayInitializer)
*/
public boolean visit(ArrayInitializer node) {
if (!isActive()) {
return false;
}
ITypeBinding typeBinding = resolveTypeBinding(node);
if (typeBinding != null) {
int dimension= typeBinding.getDimensions();
String signature= getTypeSignature(typeBinding.getElementType());
push(new ArrayInitializerInstruction(signature, node.expressions().size(), dimension, fCounter));
}
return true;
}
/**
* @see ASTVisitor#visit(ArrayType)
*/
public boolean visit(ArrayType node) {
if (!isActive()) {
return false;
}
ITypeBinding arrayTypeBinding= resolveTypeBinding(node);
if (arrayTypeBinding != null) {
int dimension= arrayTypeBinding.getDimensions();
String signature= getTypeSignature(arrayTypeBinding.getElementType());
push(new PushArrayType(signature, dimension, fCounter));
}
return false;
}
/**
* @see ASTVisitor#visit(AssertStatement)
*/
public boolean visit(AssertStatement node) {
if (!isActive()) {
return false;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Assert_statement_cannot_be_used_in_an_evaluation_expression_3);
return false;
}
/**
* @see ASTVisitor#visit(Assignment)
*/
public boolean visit(Assignment node) {
if (!isActive()) {
return false;
}
Expression leftHandSide= node.getLeftHandSide();
Expression rightHandSide= node.getRightHandSide();
int variableTypeId = getTypeId(leftHandSide);
int valueTypeId = getTypeId(rightHandSide);
String opToken = node.getOperator().toString();
int opTokenLength = opToken.length();
char char0 = opToken.charAt(0);
char char2 = '\0';
if (opTokenLength > 2) {
char2 = opToken.charAt(2);
}
ITypeBinding rightBinding = resolveTypeBinding(rightHandSide);
if (rightBinding == null) {
return false;
}
ITypeBinding leftBinding = resolveTypeBinding(leftHandSide);
if (leftBinding == null) {
return false;
}
if (variableTypeId == Instruction.T_Object) {
// If the variable is an object, the value may need to be boxed for
// the simple assignment.
// For the compound assignment operators, the value of the variable
// have to be un-boxed before the operation is done, then re-boxed to
// to be stored in the variable.
int unboxedVariableTypeId= getUnBoxedTypeId(leftHandSide);
int unboxedValueTypeId= getUnBoxedTypeId(rightHandSide);
int unboxedResultTypeId= Instruction.getBinaryPromotionType(unboxedVariableTypeId, unboxedValueTypeId);
push(new AssignmentOperator(variableTypeId, variableTypeId, fCounter));
leftHandSide.accept(this);
if (char0 == '=') {
boolean storeRequired= false;
if (rightBinding.isPrimitive()) {
boxing(leftBinding, rightBinding);
storeRequired= true;
}
rightHandSide.accept(this);
if (storeRequired) {
storeInstruction(); // boxing
}
} else {
boolean unrecognized = false;
boxing(leftBinding, rightBinding);
switch (char0) {
case '=': // equal
break;
case '+': // plus equal
push(new PlusOperator(unboxedVariableTypeId, unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
case '-': // minus equal
push(new MinusOperator(unboxedVariableTypeId, unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
case '*': // multiply equal
push(new MultiplyOperator(unboxedVariableTypeId, unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
case '/': // divide equal
push(new DivideOperator(unboxedVariableTypeId, unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
case '%': // remainder equal
push(new RemainderOperator(unboxedVariableTypeId, unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
case '^': // XOr equal
push(new XorOperator(unboxedVariableTypeId, unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
case '|': // or equal
push(new OrOperator(unboxedVariableTypeId, unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
case '&': // and equal
push(new AndOperator(unboxedVariableTypeId, unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
case '<': // left shift equal
push(new LeftShiftOperator(unboxedVariableTypeId, unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
case '>': // right shift equal or unsigned right shift equal
switch (char2) {
case '=': // right shift equal
push(new RightShiftOperator(unboxedVariableTypeId, unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
case '>': // unsigned right shift equal
push(new UnsignedRightShiftOperator(unboxedVariableTypeId, unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
default:
unrecognized = true;
break;
}
break;
default:
unrecognized = true;
break;
}
if (unrecognized) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Unrecognized_assignment_operator____4 + opToken);
return false;
}
unBoxing(leftBinding);
push(new Dup());
storeInstruction(); // dupe
storeInstruction(); // un-boxing
boolean storeRequired= unBoxing(rightBinding);
rightHandSide.accept(this);
if (storeRequired) {
storeInstruction(); // un-boxing
}
storeInstruction(); // operation
storeInstruction(); // boxing
}
} else {
boolean unrecognized = false;
switch (char0) {
case '=': // equal
push(new AssignmentOperator(variableTypeId, valueTypeId, fCounter));
break;
case '+': // plus equal
push(new PlusAssignmentOperator(variableTypeId, valueTypeId, fCounter));
break;
case '-': // minus equal
push(new MinusAssignmentOperator(variableTypeId, valueTypeId, fCounter));
break;
case '*': // multiply equal
push(new MultiplyAssignmentOperator(variableTypeId, valueTypeId, fCounter));
break;
case '/': // divide equal
push(new DivideAssignmentOperator(variableTypeId, valueTypeId, fCounter));
break;
case '%': // remainder equal
push(new RemainderAssignmentOperator(variableTypeId, valueTypeId, fCounter));
break;
case '^': // XOr equal
push(new XorAssignmentOperator(variableTypeId, valueTypeId, fCounter));
break;
case '|': // or equal
push(new OrAssignmentOperator(variableTypeId, valueTypeId, fCounter));
break;
case '&': // and equal
push(new AndAssignmentOperator(variableTypeId, valueTypeId, fCounter));
break;
case '<': // left shift equal
push(new LeftShiftAssignmentOperator(variableTypeId, valueTypeId, fCounter));
break;
case '>': // right shift equal or unsigned right shift equal
switch (char2) {
case '=': // right shift equal
push(new RightShiftAssignmentOperator(variableTypeId, valueTypeId, fCounter));
break;
case '>': // unsigned right shift equal
push(new UnsignedRightShiftAssignmentOperator(variableTypeId, valueTypeId, fCounter));
break;
default:
unrecognized = true;
break;
}
break;
default:
unrecognized = true;
break;
}
if (unrecognized) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Unrecognized_assignment_operator____4 + opToken);
return false;
}
leftHandSide.accept(this);
boolean storeRequired= unBoxing(rightBinding);
rightHandSide.accept(this);
if (storeRequired) {
storeInstruction();
}
}
return false;
}
/**
* @see ASTVisitor#visit(Block)
*/
public boolean visit(Block node) {
int start= node.getStartPosition();
if (start == fStartPosition || start == (fStartPosition + 1)) {
setActive(true);
}
if (!isActive()) {
return true;
}
push(new NoOp(fCounter));
return true;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.BlockComment)
*/
public boolean visit(BlockComment node) {
return false;
}
/**
* @see ASTVisitor#visit(BooleanLiteral)
*/
public boolean visit(BooleanLiteral node) {
if (!isActive()) {
return false;
}
push(new PushBoolean(node.booleanValue()));
return true;
}
/**
* @see ASTVisitor#visit(BreakStatement)
*/
public boolean visit(BreakStatement node) {
if (!isActive()) {
return false;
}
// create the equivalent jump instruction in the instruction
// and add an element in the list of pending break and continue
// instructions
Jump instruction= new Jump();
SimpleName labelName= node.getLabel();
String label= null;
if (labelName != null) {
label= labelName.getIdentifier();
}
push(instruction);
fCompleteInstructions.add(new CompleteInstruction(instruction, label, true));
return false;
}
/**
* @see ASTVisitor#visit(CastExpression)
*/
public boolean visit(CastExpression node) {
if (!isActive()) {
return false;
}
Type type= node.getType();
int typeId= getTypeId(type);
ITypeBinding typeBinding= resolveTypeBinding(type);
if (typeBinding != null) {
String baseTypeSignature;
int dimension= typeBinding.getDimensions();
if (typeBinding.isArray()) {
typeBinding= typeBinding.getElementType();
}
baseTypeSignature= getTypeName(typeBinding);
push(new Cast(typeId, baseTypeSignature, dimension, fCounter));
node.getExpression().accept(this);
}
return false;
}
/**
* @see ASTVisitor#visit(CatchClause)
*/
public boolean visit(CatchClause node) {
if (!isActive()) {
return false;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Catch_clause_cannot_be_used_in_an_evaluation_expression_6);
return false;
}
/**
* @see ASTVisitor#visit(CharacterLiteral)
*/
public boolean visit(CharacterLiteral node) {
if (!isActive()) {
return false;
}
push(new PushChar(node.charValue()));
return true;
}
/**
* return false, visit expression, type name & arguments, don't visit body declaration
* @see ASTVisitor#visit(ClassInstanceCreation)
*/
public boolean visit(ClassInstanceCreation node) {
if (!isActive()) {
return true;
}
if (node.getAnonymousClassDeclaration() != null) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Anonymous_type_declaration_cannot_be_used_in_an_evaluation_expression_7);
}
IMethodBinding methodBinding= node.resolveConstructorBinding();
if (methodBinding == null) {
setHasError(true);
addErrorMessage(MessageFormat.format(EvaluationEngineMessages.ASTInstructionCompiler_1, new String[]{node.toString()}));
return false;
}
ITypeBinding typeBinding= methodBinding.getDeclaringClass();
boolean isInstanceMemberType= typeBinding.isMember() && ! Modifier.isStatic(typeBinding.getModifiers());
if (isALocalType(typeBinding)) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Constructor_of_a_local_type_cannot_be_used_in_an_evaluation_expression_8);
}
if (containsALocalType(methodBinding)) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Constructor_which_contains_a_local_type_as_parameter_cannot_be_used_in_an_evaluation_expression_30);
}
if (hasErrors()) {
return false;
}
int paramCount= methodBinding.getParameterTypes().length;
String enclosingTypeSignature= null;
ITypeBinding enclosingTypeBinding= null;
if (isInstanceMemberType) {
enclosingTypeBinding= typeBinding.getDeclaringClass();
if (enclosingTypeBinding == null) {
setHasError(true);
addErrorMessage(MessageFormat.format(EvaluationEngineMessages.ASTInstructionCompiler_2, new String[]{typeBinding.getQualifiedName()}));
return false;
}
enclosingTypeSignature= getTypeSignature(enclosingTypeBinding);
paramCount++;
}
String signature= getMethodSignature(methodBinding, enclosingTypeSignature).replace('.','/');
push(new Constructor(signature, paramCount, fCounter));
push(new PushType(getTypeName(typeBinding)));
storeInstruction();
if (isInstanceMemberType) {
Expression optionalExpression= node.getExpression();
if (optionalExpression != null) {
optionalExpression.accept(this);
} else {
// for a non-static inner class, check if we are not in a static context (method)
ASTNode parent= node;
do {
parent= parent.getParent();
} while (! (parent instanceof MethodDeclaration));
if (Modifier.isStatic(((MethodDeclaration)parent).getModifiers())) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Must_explicitly_qualify_the_allocation_with_an_instance_of_the_enclosing_type_33);
return false;
}
push(new PushThis(getEnclosingLevel(node, enclosingTypeBinding)));
storeInstruction();
}
}
List arguments = node.arguments();
pushMethodArguments(methodBinding, arguments);
return false;
}
/**
* @see ASTVisitor#visit(CompilationUnit)
*/
public boolean visit(CompilationUnit node) {
return true;
}
/**
* @see ASTVisitor#visit(ConditionalExpression)
*/
public boolean visit(ConditionalExpression node) {
if (!isActive()) {
return true;
}
push(new NoOp(fCounter));
return true;
}
/**
* @see ASTVisitor#visit(ConstructorInvocation)
*/
public boolean visit(ConstructorInvocation node) {
if (!isActive()) {
return false;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_this_constructor_invocation_cannot_be_used_in_an_evaluation_expression_9);
return false;
}
/**
* @see ASTVisitor#visit(ContinueStatement)
*/
public boolean visit(ContinueStatement node) {
if (!isActive()) {
return false;
}
// create the equivalent jump instruction in the instruction
// and add an element in the list of pending break and continue
// instructions
Jump instruction= new Jump();
SimpleName labelName= node.getLabel();
String label= null;
if (labelName != null) {
label= labelName.getIdentifier();
}
push(instruction);
fCompleteInstructions.add(new CompleteInstruction(instruction, label, false));
return false;
}
/**
* @see ASTVisitor#visit(DoStatement)
*/
public boolean visit(DoStatement node) {
if (!isActive()) {
return false;
}
push(new NoOp(fCounter));
return true;
}
/**
* @see ASTVisitor#visit(EmptyStatement)
*/
public boolean visit(EmptyStatement node) {
if (!isActive()) {
return false;
}
push(new NoOp(fCounter));
return true;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.EnhancedForStatement)
*/
public boolean visit(EnhancedForStatement node) {
if (!isActive()) {
return false;
}
push(new NoOp(fCounter));
ITypeBinding typeBinding= resolveTypeBinding(node.getExpression());
if (typeBinding == null) {
return false;
}
Type paramType= node.getParameter().getType();
ITypeBinding paramBinding = resolveTypeBinding(paramType);
if (paramBinding == null) {
return false;
}
String typeSignature= getTypeSignature(paramBinding);
int paramTypeId= getTypeId(paramType);
boolean isParamPrimitiveType= paramTypeId != Instruction.T_Object && paramTypeId != Instruction.T_String;
String paramIdentifier= node.getParameter().getName().getIdentifier();
if (typeBinding.isArray()) {
// the expression returns an array
int idIndex= fUniqueIdIndex++;
String arrayIdentifier= "#a" + idIndex; //$NON-NLS-1$
String varIdentifier= "#i" + idIndex; //$NON-NLS-1$
push(new LocalVariableCreation(arrayIdentifier, typeSignature, 1, isParamPrimitiveType, true, fCounter));
node.getExpression().accept(this);
storeInstruction();
push(new LocalVariableCreation(varIdentifier, "I", 0, true, true, fCounter)); //$NON-NLS-1$
push(new PushInt(0));
storeInstruction();
storeInstruction();
push(new LocalVariableCreation(paramIdentifier, typeSignature, 0, isParamPrimitiveType, false, fCounter));
storeInstruction();
push(new LessOperator(Instruction.T_int, Instruction.T_int, fCounter));
push(new PushLocalVariable(varIdentifier));
storeInstruction();
push(new PushArrayLength(fCounter));
push(new PushLocalVariable(arrayIdentifier));
storeInstruction();
storeInstruction();
storeInstruction();
// conditional jump will be added here
push(new NoOp(fCounter));
push(new AssignmentOperator(paramTypeId, paramTypeId, fCounter));
push(new PushLocalVariable(paramIdentifier));
storeInstruction();
push(new org.eclipse.jdt.internal.debug.eval.ast.instructions.ArrayAccess(fCounter));
push(new PushLocalVariable(arrayIdentifier));
storeInstruction();
push(new PostfixPlusPlusOperator(Instruction.T_int, fCounter));
push(new PushLocalVariable(varIdentifier));
storeInstruction();
storeInstruction();
storeInstruction();
if (checkAutoBoxing(typeBinding.getElementType(), paramBinding)) {
storeInstruction();
}
storeInstruction();
addPopInstruction();
node.getBody().accept(this);
storeInstruction();
// jump will be added here
} else {
// the expression returns a collection
String iteratorIdentifier= "#i" + fUniqueIdIndex++; //$NON-NLS-1$
push(new LocalVariableCreation(iteratorIdentifier, "Ljava/util/Iterator;", 0, false, true, fCounter)); //$NON-NLS-1$
push(new SendMessage("iterator", "()Ljava/util/Iterator;", 0, null, fCounter)); //$NON-NLS-1$//$NON-NLS-2$
node.getExpression().accept(this);
storeInstruction();
storeInstruction();
push(new LocalVariableCreation(paramIdentifier, typeSignature, 0, isParamPrimitiveType, false, fCounter));
storeInstruction();
push(new SendMessage("hasNext", "()Z", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
push(new PushLocalVariable(iteratorIdentifier));
storeInstruction();
storeInstruction();
// conditional jump will be added here
push(new NoOp(fCounter));
push(new AssignmentOperator(paramTypeId, paramTypeId, fCounter));
push(new PushLocalVariable(paramIdentifier));
storeInstruction();
push(new SendMessage("next", "()Ljava/lang/Object;", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
push(new PushLocalVariable(iteratorIdentifier));
storeInstruction();
storeInstruction();
if (checkAutoBoxing(typeBinding.getTypeArguments()[0], paramBinding)) {
storeInstruction();
}
storeInstruction();
addPopInstruction();
node.getBody().accept(this);
storeInstruction();
// jump will be added here
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.EnumConstantDeclaration)
*/
public boolean visit(EnumConstantDeclaration node) {
if (!isActive()) {
return true;
}
// nothing to do, we shouldn't hit this node
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.EnumDeclaration)
*/
public boolean visit(EnumDeclaration node) {
if (!isActive()) {
return true;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_0);
return false;
}
/**
* @see ASTVisitor#visit(ExpressionStatement)
*/
public boolean visit(ExpressionStatement node) {
return true;
}
/**
* return false, visit expression, don't visit name
*
* @see ASTVisitor#visit(FieldAccess)
*/
public boolean visit(FieldAccess node) {
if (!isActive()) {
return false;
}
SimpleName fieldName= node.getName();
IVariableBinding fieldBinding= (IVariableBinding) fieldName.resolveBinding();
if(fieldBinding != null) {
ITypeBinding declaringTypeBinding= fieldBinding.getDeclaringClass();
Expression expression = node.getExpression();
String fieldId = fieldName.getIdentifier();
if (Modifier.isStatic(fieldBinding.getModifiers())) {
push(new PushStaticFieldVariable(fieldId, getTypeName(declaringTypeBinding), fCounter));
expression.accept(this);
addPopInstruction();
} else {
if (declaringTypeBinding == null) { // it is a field without declaring type => it is the special length array field
push(new PushArrayLength(fCounter));
} else {
if (isALocalType(declaringTypeBinding)) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Qualified_local_type_field_access_cannot_be_used_in_an_evaluation_expression_31);
return false;
}
push(new PushFieldVariable(fieldId, getTypeSignature(declaringTypeBinding), fCounter));
}
expression.accept(this);
}
}
return false;
}
/**
* @see ASTVisitor#visit(FieldDeclaration)
*/
public boolean visit(FieldDeclaration node) {
return true;
}
/**
* @see ASTVisitor#visit(ForStatement)
* return <code>false</code>, don't use the standard accept order.
* order used for visiting children :
* initializers, condition, body, updaters
*/
public boolean visit(ForStatement node) {
if (!isActive()) {
return false;
}
push(new NoOp(fCounter));
push(new NoOp(fCounter));
for (Iterator iter= node.initializers().iterator(); iter.hasNext();) {
Expression expr= (Expression) iter.next();
expr.accept(this);
addPopInstructionIfNeeded(expr);
}
storeInstruction();
Expression condition= node.getExpression();
if (condition != null) {
condition.accept(this);
}
node.getBody().accept(this);
push(new NoOp(fCounter));
for (Iterator iter= node.updaters().iterator(); iter.hasNext();) {
Expression expr= (Expression) iter.next();
expr.accept(this);
addPopInstructionIfNeeded(expr);
}
storeInstruction();
return false;
}
/**
* @see ASTVisitor#visit(IfStatement)
*/
public boolean visit(IfStatement node) {
if (!isActive()) {
return false;
}
push(new NoOp(fCounter));
return true;
}
/**
* @see ASTVisitor#visit(ImportDeclaration)
*/
public boolean visit(ImportDeclaration node) {
return false;
}
/**
* return <code>false</code>, don't use the standard accept order.
*
* @see ASTVisitor#visit(InfixExpression)
*/
public boolean visit(InfixExpression node) {
if (!isActive()) {
return false;
}
String opToken = node.getOperator().toString();
int opTokenLength = opToken.length();
char char0 = opToken.charAt(0);
char char1 = '\0';
char char2 = '\0';
if (opTokenLength > 1) {
char1 = opToken.charAt(1);
if (opTokenLength > 2) {
char2 = opToken.charAt(2);
}
}
List extendedOperands = node.extendedOperands();
int operatorNumber=extendedOperands.size() + 1;
int[][] types = new int[operatorNumber][3];
Iterator iterator = extendedOperands.iterator();
Expression leftOperand= node.getLeftOperand();
Expression rightOperand= node.getRightOperand();
int leftTypeId;
int rightTypeId;
boolean unbox = false;
// for == and != un-box when at least operand is primitive (otherwise compare the objects)
ITypeBinding leftBinding = resolveTypeBinding(leftOperand);
if (leftBinding == null) {
return false;
}
ITypeBinding rightBinding = resolveTypeBinding(rightOperand);
if (rightBinding == null) {
return false;
}
if ((char0 == '=' || char0 == '!') && char1 == '=') {
unbox = leftBinding.isPrimitive() || rightBinding.isPrimitive();
} else {
unbox = true;
}
if (unbox) {
leftTypeId= getUnBoxedTypeId(leftOperand);
rightTypeId = getUnBoxedTypeId(rightOperand);
} else {
leftTypeId= getTypeId(leftOperand);
rightTypeId = getTypeId(rightOperand);
}
int resultTypeId = Instruction.getBinaryPromotionType(leftTypeId, rightTypeId);
types[0][0] = resultTypeId;
types[0][1] = leftTypeId;
types[0][2] = rightTypeId;
for (int i = 1; i < operatorNumber; i++) {
Expression operand = (Expression) iterator.next();
leftTypeId = resultTypeId;
rightTypeId = getUnBoxedTypeId(operand);
resultTypeId = Instruction.getBinaryPromotionType(leftTypeId, rightTypeId);
types[i][0] = resultTypeId;
types[i][1] = leftTypeId;
types[i][2] = rightTypeId;
}
boolean unrecognized= false;
switch (char0) {
case '*': // multiply
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new MultiplyOperator(types[i][0], types[i][1], types[i][2], fCounter));
}
break;
case '/': // divide
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new DivideOperator(types[i][0], types[i][1], types[i][2], fCounter));
}
break;
case '%': // remainder
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new RemainderOperator(types[i][0], types[i][1], types[i][2], fCounter));
}
break;
case '+': // plus
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new PlusOperator(types[i][0], types[i][1], types[i][2], fCounter));
}
break;
case '-': // minus
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new MinusOperator(types[i][0], types[i][1], types[i][2], fCounter));
}
break;
case '<': // left shift or less or less equal
switch (char1) {
case '\0': // less
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new LessOperator(types[i][1], types[i][2], fCounter));
}
break;
case '<': // left shift
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new LeftShiftOperator(Instruction.getUnaryPromotionType(types[i][1]), types[i][1], types[i][2], fCounter));
}
break;
case '=': // less equal
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new LessEqualOperator(types[i][1], types[i][2], fCounter));
}
break;
default:
unrecognized= true;
break;
}
break;
case '>': // right shift or unsigned right shift or greater or greater equal
switch (char1) {
case '\0': // greater
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new GreaterOperator(types[i][1], types[i][2], fCounter));
}
break;
case '>': // right shift or unsigned right shift
switch (char2) {
case '\0': // right shift
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new RightShiftOperator(Instruction.getUnaryPromotionType(types[i][1]), types[i][1], types[i][2], fCounter));
}
break;
case '>': // unsigned right shift
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new UnsignedRightShiftOperator(Instruction.getUnaryPromotionType(types[i][1]), types[i][1], types[i][2], fCounter));
}
break;
}
break;
case '=': // greater equal
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new GreaterEqualOperator(types[i][1], types[i][2], fCounter));
}
break;
default:
unrecognized= true;
break;
}
break;
case '=': // equal equal
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new EqualEqualOperator(types[i][1], types[i][2], true, fCounter));
}
break;
case '!': // not equal
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new EqualEqualOperator(types[i][1], types[i][2], false, fCounter));
}
break;
case '^': // XOr
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new XorOperator(types[i][0], types[i][1], types[i][2], fCounter));
}
break;
case '|': // or or or or
switch (char1) {
case '\0': // or
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new OrOperator(types[i][0], types[i][1], types[i][2], fCounter));
}
break;
case '|': // or or
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new NoOp(fCounter));
}
break;
default:
unrecognized= true;
break;
}
break;
case '&': // and or and and
switch (char1) {
case '\0': // and
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new AndOperator(types[i][0], types[i][1], types[i][2], fCounter));
}
break;
case '&': // and and
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new NoOp(fCounter));
}
break;
default:
unrecognized= true;
break;
}
break;
default:
unrecognized= true;
break;
}
if (unrecognized) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Unrecognized_infix_operator____13 + opToken);
}
if (hasErrors()) {
return false;
}
iterator = extendedOperands.iterator();
if ((char0 == '&' && char1 == '&') || (char0 == '|' && char1 == '|')) { // and and operator
boolean isOrOr= char0 == '|';
ConditionalJump[] conditionalJumps= new ConditionalJump[operatorNumber];
int[] conditionalJumpAddresses = new int[operatorNumber];
boolean storeRequired= unBoxing(leftBinding);
leftOperand.accept(this);
if (storeRequired) {
storeInstruction();
}
ConditionalJump conditionalJump= new ConditionalJump(isOrOr);
conditionalJumps[0]= conditionalJump;
conditionalJumpAddresses[0] = fCounter;
push(conditionalJump);
storeInstruction();
storeRequired= unBoxing(rightBinding);
rightOperand.accept(this);
if (storeRequired) {
storeInstruction();
}
for (int i= 1; i < operatorNumber; i ++) {
conditionalJump= new ConditionalJump(isOrOr);
conditionalJumps[i]= conditionalJump;
conditionalJumpAddresses[i] = fCounter;
push(conditionalJump);
storeInstruction();
Expression operand= (Expression) iterator.next();
ITypeBinding typeBinding = resolveTypeBinding(operand);
if (typeBinding == null) {
return false;
}
storeRequired= unBoxing(typeBinding);
operand.accept(this);
if (storeRequired) {
storeInstruction();
}
}
Jump jump = new Jump();
jump.setOffset(1);
push(jump);
storeInstruction();
for (int i= 0; i < operatorNumber; i ++) {
conditionalJumps[i].setOffset(fCounter - conditionalJumpAddresses[i] - 1);
}
push(new PushBoolean(isOrOr));
storeInstruction();
// store the no-op
storeInstruction();
} else { // other operators
boolean storeRequired= false;
if (unbox) {
storeRequired= unBoxing(leftBinding);
}
leftOperand.accept(this);
if (storeRequired) {
storeInstruction();
}
if (unbox) {
storeRequired= unBoxing(rightBinding);
}
rightOperand.accept(this);
if (storeRequired) {
storeInstruction();
}
storeInstruction();
for (int i= 1; i < operatorNumber; i ++) {
Expression operand= (Expression) iterator.next();
if (unbox) {
ITypeBinding typeBinding = resolveTypeBinding(operand);
if (typeBinding == null) {
return false;
}
storeRequired= unBoxing(typeBinding);
}
operand.accept(this);
if (storeRequired) {
storeInstruction();
}
storeInstruction();
}
}
return false;
}
/**
* @see ASTVisitor#visit(Initializer)
*/
public boolean visit(Initializer node) {
return true;
}
/**
* @see ASTVisitor#visit(InstanceofExpression)
*/
public boolean visit(InstanceofExpression node) {
if (!isActive()) {
return false;
}
push(new InstanceOfOperator(fCounter));
return true;
}
/**
* @see ASTVisitor#visit(Javadoc)
*/
public boolean visit(Javadoc node) {
return false;
}
/**
* @see ASTVisitor#visit(LabeledStatement)
* return <code>false</code>, don't use the standard accept order.
*/
public boolean visit(LabeledStatement node) {
node.getBody().accept(this);
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.LineComment)
*/
public boolean visit(LineComment node) {
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MarkerAnnotation)
*/
public boolean visit(MarkerAnnotation node) {
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MemberRef)
*/
public boolean visit(MemberRef node) {
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MemberValuePair)
*/
public boolean visit(MemberValuePair node) {
return false;
}
/**
* @see ASTVisitor#visit(MethodDeclaration)
*/
public boolean visit(MethodDeclaration node) {
int start= node.getStartPosition();
int end= start + node.getLength();
if (start < fStartPosition && end > fStartPosition) {
return true;
}
return false;
}
/**
* return false, don't visit name, visit expression & arguments
*
* @see ASTVisitor#visit(MethodInvocation)
*/
public boolean visit(MethodInvocation node) {
if (!isActive()) {
return false;
}
IMethodBinding methodBinding= (IMethodBinding) node.getName().resolveBinding();
if (methodBinding == null) {
// could be the receiver is not visible - for example a private field access from super class
ASTNode root = node.getRoot();
if (root instanceof CompilationUnit) {
CompilationUnit cu = (CompilationUnit) root;
IProblem[] problems = cu.getProblems();
for (int i = 0; i < problems.length; i++) {
IProblem problem = problems[i];
setHasError(true);
addErrorMessage(problem.getMessage());
}
}
}
if (hasErrors()) {
return false;
}
if (containsALocalType(methodBinding)) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Method_which_contains_a_local_type_as_parameter_cannot_be_used_in_an_evaluation_expression_32);
return false;
}
int paramCount = methodBinding.getParameterTypes().length;
String selector= methodBinding.getName();
String signature= getMethodSignature(methodBinding, null).replace('.','/');
boolean isStatic= Flags.isStatic(methodBinding.getModifiers());
Expression expression= node.getExpression();
if (isStatic) {
String typeName= getTypeName(methodBinding.getDeclaringClass());
push(new SendStaticMessage(typeName, selector, signature, paramCount, fCounter));
if (expression != null) {
node.getExpression().accept(this);
addPopInstruction();
}
} else {
push(new SendMessage(selector, signature, paramCount, null, fCounter));
if (expression == null) {
push(new PushThis(getEnclosingLevel(node, methodBinding.getDeclaringClass())));
storeInstruction();
} else {
node.getExpression().accept(this);
}
}
List arguments = node.arguments();
pushMethodArguments(methodBinding, arguments);
return false;
}
/**
* Pushes method arguments onto the stack for a method or constructor invocation taking
* variable arguments and auto-boxing into consideration.
*
* @param methodBinding method or constructor being called
* @param arguments argument list
*/
private void pushMethodArguments(IMethodBinding methodBinding, List arguments) {
int argCount = arguments.size();
ITypeBinding[] parameterTypes = methodBinding.getParameterTypes();
int paramCount = parameterTypes.length;
ITypeBinding lastArgBinding = null;
if (methodBinding.isVarargs()) {
Expression lastArg = (Expression)arguments.get(argCount - 1);
lastArgBinding = resolveTypeBinding(lastArg);
if (lastArgBinding == null) {
return;
}
}
if (methodBinding.isVarargs() && !(paramCount == argCount && parameterTypes[paramCount - 1].getDimensions() == lastArgBinding.getDimensions())) {
// if this method is a varargs, and if the method is invoked using the varargs syntax
// (multiple arguments) and not an array
Iterator iterator= arguments.iterator();
// process the first arguments (no part of the variable argument)
for (int i= 0; i < paramCount - 1; i++) {
Expression argument= (Expression)iterator.next();
boolean storeRequired= checkAutoBoxing(argument.resolveTypeBinding(), parameterTypes[i]);
argument.accept(this);
if (storeRequired) {
storeInstruction();
}
}
// create a array of the remainder arguments
ITypeBinding varargsParameterType= parameterTypes[paramCount - 1];
ITypeBinding varargsElementType= varargsParameterType.getElementType();
push(new ArrayInitializerInstruction(getTypeSignature(varargsElementType), argCount - paramCount + 1, varargsParameterType.getDimensions(), fCounter));
while (iterator.hasNext()) {
Expression argument= (Expression) iterator.next();
boolean storeRequired= checkAutoBoxing(argument.resolveTypeBinding(), varargsElementType);
argument.accept(this);
if (storeRequired) {
storeInstruction();
}
}
storeInstruction();
} else {
Iterator iterator= arguments.iterator();
int i= 0;
while (iterator.hasNext()) {
Expression argument= (Expression) iterator.next();
boolean storeRequired= checkAutoBoxing(argument.resolveTypeBinding(), parameterTypes[i++]);
argument.accept(this);
if (storeRequired) {
storeInstruction();
}
}
}
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodRef)
*/
public boolean visit(MethodRef node) {
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodRefParameter)
*/
public boolean visit(MethodRefParameter node) {
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Modifier)
*/
public boolean visit(Modifier node) {
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.NormalAnnotation)
*/
public boolean visit(NormalAnnotation node) {
return false;
}
/**
* @see ASTVisitor#visit(NullLiteral)
*/
public boolean visit(NullLiteral node) {
if (!isActive()) {
return false;
}
push(new PushNull());
return true;
}
/**
* @see ASTVisitor#visit(NumberLiteral)
*/
public boolean visit(NumberLiteral node) {
if (!isActive()) {
return false;
}
int literalType= getTypeId(node);
String token= node.getToken();
int tokenLastCharOffset= token.length() - 1;
char lastChar= token.charAt(tokenLastCharOffset);
String subToken= token.substring(0, tokenLastCharOffset);
switch (literalType) {
case Instruction.T_int:
push(new PushInt(parseIntValue(token)));
break;
case Instruction.T_long:
push(new PushLong(parseLongValue(subToken)));
break;
case Instruction.T_float:
push(new PushFloat(Float.parseFloat(subToken)));
break;
case Instruction.T_double:
if (lastChar == 'D' || lastChar == 'd') {
push(new PushDouble(Double.parseDouble(subToken)));
} else {
push(new PushDouble(Double.parseDouble(token)));
}
break;
}
return true;
}
/**
* Method parseIntValue.
* @param token
*/
private int parseIntValue(String token) {
int tokenLength= token.length();
if (tokenLength < 10) {
// Integer.decode can handle tokens with less than 10 digits
return Integer.decode(token).intValue();
}
switch (getBase(token)) {
case 8:
return (Integer.decode(token.substring(0, tokenLength - 1)).intValue() << 3) | Integer.decode("0" + token.charAt(tokenLength - 1)).intValue(); //$NON-NLS-1$
case 10:
return Integer.decode(token).intValue();
case 16:
return (Integer.decode(token.substring(0, tokenLength - 1)).intValue() << 4) | Integer.decode("0x" + token.charAt(tokenLength - 1)).intValue(); //$NON-NLS-1$
default:
// getBase(String) only returns 8, 10, or 16. This code is unreachable
return 0;
}
}
/**
* Method parseLongValue.
* @param token
*/
private long parseLongValue(String token) {
int tokenLength= token.length();
if (tokenLength < 18) {
// Long.decode can handle tokens with less than 18 digits
return Long.decode(token).longValue();
}
switch (getBase(token)) {
case 8:
return (Long.decode(token.substring(0, tokenLength - 1)).longValue() << 3) | Long.decode("0" + token.charAt(tokenLength - 1)).longValue(); //$NON-NLS-1$
case 10:
return Long.decode(token).longValue();
case 16:
return (Long.decode(token.substring(0, tokenLength - 1)).longValue() << 4) | Long.decode("0x" + token.charAt(tokenLength - 1)).longValue(); //$NON-NLS-1$
default:
// getBase(String) only returns 8, 10, or 16. This code is unreachable
return 0;
}
}
/**
* Returns the numeric base for the given token
* according to the Java specification. Returns
* 8, 10, or 16.
*/
private int getBase(String token) {
if (token.charAt(0) == '0') {
if (token.charAt(1) == 'x') {
return 16; // "0x" prefix: Hexadecimal
}
return 8; // "0" prefix: Octal
}
return 10; // No prefix: Decimal
}
/**
* @see ASTVisitor#visit(PackageDeclaration)
*/
public boolean visit(PackageDeclaration node) {
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ParameterizedType)
*/
public boolean visit(ParameterizedType node) {
if (!isActive()) {
return false;
}
ITypeBinding typeBinding = resolveTypeBinding(node);
if (typeBinding != null) {
push(new PushType(getTypeName(typeBinding)));
}
return false;
}
/**
* @see ASTVisitor#visit(ParenthesizedExpression)
*/
public boolean visit(ParenthesizedExpression node) {
if (!isActive()) {
return false;
}
return true;
}
/**
* @see ASTVisitor#visit(PostfixExpression)
*/
public boolean visit(PostfixExpression node) {
if (!isActive()) {
return false;
}
Expression operand= node.getOperand();
int expressionTypeId = getTypeId(operand);
String opToken = node.getOperator().toString();
char char0 = opToken.charAt(0);
if (expressionTypeId == Instruction.T_Object) {
int expressionUnBoxedTypeId= getUnBoxedTypeId(operand);
AssignmentOperator assignmentInstruction= new AssignmentOperator(Instruction.T_Object, Instruction.T_Object, fCounter);
push(assignmentInstruction);
operand.accept(this);
switch (char0) {
case '+': // plus plus
push(new PlusOperator(expressionUnBoxedTypeId, expressionUnBoxedTypeId, expressionUnBoxedTypeId, fCounter));
break;
case '-': // minus minus
push(new MinusOperator(expressionUnBoxedTypeId, expressionUnBoxedTypeId, expressionUnBoxedTypeId, fCounter));
break;
default:
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_unrecognized_postfix_operator____15 + opToken);
return false;
}
push(new Value(fCounter));
push(new Dup());
storeInstruction(); // dupe
storeInstruction(); // value
push(new DupX1());
storeInstruction(); // dup_x1
ITypeBinding typeBinding = resolveTypeBinding(operand);
if (typeBinding == null) {
return false;
}
unBoxing(typeBinding);
storeInstruction(); // un-boxing
push(new PushInt(1));
storeInstruction(); // push 1
storeInstruction(); // operator
boxing(typeBinding, null);
storeInstruction(); // boxing
storeInstruction(); // assignment
push(new Pop(assignmentInstruction.getSize() + 1));
return false;
}
switch (char0) {
case '+': // plus plus
push(new PostfixPlusPlusOperator(expressionTypeId, fCounter));
break;
case '-': // minus minus
push(new PostfixMinusMinusOperator(expressionTypeId, fCounter));
break;
default:
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_unrecognized_postfix_operator____15 + opToken);
return false;
}
return true;
}
/**
* @see ASTVisitor#visit(PrefixExpression)
*/
public boolean visit(PrefixExpression node) {
if (!isActive()) {
return false;
}
Expression operand= node.getOperand();
int expressionTypeId = getTypeId(operand);
String opToken = node.getOperator().toString();
int opTokenLength = opToken.length();
char char0 = opToken.charAt(0);
char char1 = '\0';
if (opTokenLength > 1) {
char1 = opToken.charAt(1);
}
boolean unrecognized = false;
if (expressionTypeId == Instruction.T_Object) {
int expressionUnBoxedTypeId= getUnBoxedTypeId(operand);
ITypeBinding typeBinding = resolveTypeBinding(operand);
if (typeBinding == null) {
return false;
}
if (char1 == '\0') {
switch (char0) {
case '+': // unary plus
push(new UnaryPlusOperator(expressionUnBoxedTypeId, fCounter));
break;
case '-': // unary minus
push(new UnaryMinusOperator(expressionUnBoxedTypeId, fCounter));
break;
case '~': // twiddle
push(new TwiddleOperator(expressionUnBoxedTypeId, fCounter));
break;
case '!': // not
push(new NotOperator(expressionUnBoxedTypeId, fCounter));
break;
default:
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_unrecognized_prefix_operator____16 + opToken);
return false;
}
unBoxing(typeBinding);
operand.accept(this);
storeInstruction(); // un-boxing
} else {
// plus plus and minus minus operators
push(new AssignmentOperator(Instruction.T_Object, Instruction.T_Object, fCounter));
operand.accept(this);
boxing(typeBinding, null);
switch (char1) {
case '+':
push(new PlusOperator(expressionUnBoxedTypeId, expressionUnBoxedTypeId, expressionUnBoxedTypeId, fCounter));
break;
case '-':
push(new MinusOperator(expressionUnBoxedTypeId, expressionUnBoxedTypeId, expressionUnBoxedTypeId, fCounter));
break;
default:
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_unrecognized_prefix_operator____16 + opToken);
return false;
}
unBoxing(typeBinding);
push(new Dup());
storeInstruction(); // dupe
storeInstruction(); // un-boxing
push(new PushInt(1));
storeInstruction(); // push 1
storeInstruction(); // operator
storeInstruction(); // boxing
}
return false;
}
switch (char0) {
case '+': // plus plus or unary plus
switch (char1) {
case '\0': // unary plus
push(new UnaryPlusOperator(expressionTypeId, fCounter));
break;
case '+': // plus plus
push(new PrefixPlusPlusOperator(expressionTypeId, fCounter));
break;
default:
unrecognized= true;
break;
}
break;
case '-': // minus minus or unary minus
switch (char1) {
case '\0': // unary minus
push(new UnaryMinusOperator(expressionTypeId, fCounter));
break;
case '-': // minus minus
push(new PrefixMinusMinusOperator(expressionTypeId, fCounter));
break;
default:
unrecognized= true;
break;
}
break;
case '~': // twiddle
push(new TwiddleOperator(expressionTypeId, fCounter));
break;
case '!': // not
push(new NotOperator(expressionTypeId, fCounter));
break;
default:
unrecognized= true;
break;
}
if (unrecognized) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_unrecognized_prefix_operator____16 + opToken);
return false;
}
return true;
}
/**
* @see ASTVisitor#visit(PrimitiveType)
*/
public boolean visit(PrimitiveType node) {
if (!isActive()) {
return false;
}
ITypeBinding typeBinding = resolveTypeBinding(node);
if (typeBinding != null) {
push(new PushPrimitiveType(getTypeName(typeBinding)));
}
return false;
}
/**
* @see ASTVisitor#visit(QualifiedName)
*/
public boolean visit(QualifiedName node) {
if (!isActive()) {
return false;
}
if (hasErrors()) {
return true;
}
IBinding binding = resolveBinding(node);
if (binding == null) {
return false;
}
switch (binding.getKind()) {
case IBinding.TYPE:
node.getName().accept(this);
break;
case IBinding.VARIABLE:
SimpleName fieldName= node.getName();
IVariableBinding fieldBinding= (IVariableBinding) resolveBinding(fieldName);
if (fieldBinding == null) {
return false;
}
ITypeBinding declaringTypeBinding= fieldBinding.getDeclaringClass();
String fieldId = fieldName.getIdentifier();
if (Modifier.isStatic(fieldBinding.getModifiers())) {
push(new PushStaticFieldVariable(fieldId, getTypeName(declaringTypeBinding), fCounter));
} else {
if (declaringTypeBinding == null) {
push(new PushArrayLength(fCounter));
} else {
push(new PushFieldVariable(fieldId, getTypeSignature(declaringTypeBinding), fCounter));
}
node.getQualifier().accept(this);
}
storeInstruction();
break;
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.QualifiedType)
*/
public boolean visit(QualifiedType node) {
if (!isActive()) {
return false;
}
ITypeBinding typeBinding = resolveTypeBinding(node);
if (typeBinding != null) {
push(new PushType(getTypeName(typeBinding)));
}
return false;
}
/**
* @see ASTVisitor#visit(ReturnStatement)
*/
public boolean visit(ReturnStatement node) {
if (!isActive()) {
return false;
}
push(new ReturnInstruction(fCounter));
return true;
}
/**
* @see ASTVisitor#visit(SimpleName)
*/
public boolean visit(SimpleName node) {
if (!isActive()) {
return false;
}
if (hasErrors()) {
return true;
}
IBinding binding = resolveBinding(node);
if (binding == null) {
return true;
}
String variableId = node.getIdentifier();
switch (binding.getKind()) {
case IBinding.TYPE:
ITypeBinding typeBinding= (ITypeBinding) binding;
push(new PushType(getTypeName(typeBinding)));
break;
case IBinding.VARIABLE:
IVariableBinding variableBinding= (IVariableBinding) binding;
ITypeBinding declaringTypeBinding= variableBinding.getDeclaringClass();
if (variableBinding.isField()) {
if (Modifier.isStatic(variableBinding.getModifiers())) {
push(new PushStaticFieldVariable(variableId, getTypeName(declaringTypeBinding), fCounter));
} else {
if (isALocalType(declaringTypeBinding)) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_36);
return false;
}
push(new PushFieldVariable(variableId, getTypeSignature(declaringTypeBinding), fCounter));
push(new PushThis(getEnclosingLevel(node, declaringTypeBinding)));
storeInstruction();
}
} else {
push(new PushLocalVariable(variableId));
}
break;
}
return true;
}
/**
* return false, don't visit child
*
* @see ASTVisitor#visit(SimpleType)
*/
public boolean visit(SimpleType node) {
if (!isActive()) {
return false;
}
ITypeBinding typeBinding = resolveTypeBinding(node);
if (typeBinding != null) {
push(new PushType(getTypeName(typeBinding)));
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SingleMemberAnnotation)
*/
public boolean visit(SingleMemberAnnotation node) {
return false;
}
/**
* @see ASTVisitor#visit(SingleVariableDeclaration)
* return <code>false</code>, don't use the standard accept order.
*/
public boolean visit(SingleVariableDeclaration node) {
if (!isActive()) {
return false;
}
ITypeBinding typeBinding= resolveTypeBinding(node.getType());
if (typeBinding != null) {
int typeDimension= typeBinding.getDimensions();
if (typeDimension != 0) {
typeBinding= typeBinding.getElementType();
}
Expression initializer= node.getInitializer();
push(new LocalVariableCreation(node.getName().getIdentifier(), getTypeSignature(typeBinding), typeDimension, typeBinding.isPrimitive(), initializer != null, fCounter));
if (initializer != null) {
initializer.accept(this);
}
}
return false;
}
/**
* @see ASTVisitor#visit(StringLiteral)
*/
public boolean visit(StringLiteral node) {
if (!isActive()) {
return false;
}
push(new PushString(node.getLiteralValue()));
return true;
}
/**
* @see ASTVisitor#visit(SuperConstructorInvocation)
*/
public boolean visit(SuperConstructorInvocation node) {
if (!isActive()) {
return false;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_super_constructor_invocation_cannot_be_used_in_an_evaluation_expression_19);
return false;
}
/**
* @see ASTVisitor#visit(SuperFieldAccess)
*/
public boolean visit(SuperFieldAccess node) {
if (!isActive()) {
return false;
}
SimpleName fieldName= node.getName();
IVariableBinding fieldBinding= (IVariableBinding) resolveBinding(fieldName);
if (fieldBinding == null) {
return false;
}
ITypeBinding declaringTypeBinding= fieldBinding.getDeclaringClass();
String fieldId = fieldName.getIdentifier();
if (Modifier.isStatic(fieldBinding.getModifiers())) {
push(new PushStaticFieldVariable(fieldId, getTypeName(declaringTypeBinding), fCounter));
} else {
Name qualifier = node.getQualifier();
int superLevel= 1;
int enclosingLevel= 0;
if (qualifier != null) {
ITypeBinding typeBinding = resolveTypeBinding(qualifier);
if (typeBinding == null) {
return false;
}
superLevel= getSuperLevel(typeBinding, declaringTypeBinding);
ITypeBinding binding = (ITypeBinding)resolveBinding(qualifier);
if (binding == null) {
return false;
}
enclosingLevel= getEnclosingLevel(node, binding);
}
push(new PushFieldVariable(fieldId, superLevel, fCounter));
push(new PushThis(enclosingLevel));
storeInstruction();
}
return false;
}
/**
* return false, don't visit name, visit arguments
*
* @see ASTVisitor#visit(SuperMethodInvocation)
*/
public boolean visit(SuperMethodInvocation node) {
if (!isActive()) {
return false;
}
IMethodBinding methodBinding = (IMethodBinding) resolveBinding(node.getName());
if (methodBinding == null) {
return false;
}
if (containsALocalType(methodBinding)) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Method_which_contains_a_local_type_as_parameter_cannot_be_used_in_an_evaluation_expression_32);
return false;
}
ITypeBinding[] parameterTypes = methodBinding.getParameterTypes();
int paramCount = parameterTypes.length;
String selector = methodBinding.getName();
String signature = getMethodSignature(methodBinding, null);
Name qualifier= node.getQualifier();
if (Modifier.isStatic(methodBinding.getModifiers())) {
push(new SendStaticMessage(getTypeName(methodBinding.getDeclaringClass()), selector, signature, paramCount, fCounter));
} else {
push(new SendMessage(selector, signature, paramCount, getTypeSignature(methodBinding.getDeclaringClass()), fCounter));
int enclosingLevel= 0;
if (qualifier != null) {
ITypeBinding typeBinding = (ITypeBinding)resolveBinding(qualifier);
if (typeBinding == null) {
return false;
}
enclosingLevel= getEnclosingLevel(node, typeBinding);
}
push(new PushThis(enclosingLevel));
storeInstruction();
}
List arguments = node.arguments();
int argCount = arguments.size();
ITypeBinding lastArgBinding = null;
if (methodBinding.isVarargs()) {
lastArgBinding = resolveTypeBinding((Expression)arguments.get(argCount - 1));
if (lastArgBinding == null) {
return false;
}
}
if (methodBinding.isVarargs() && !(paramCount == argCount && parameterTypes[paramCount - 1].getDimensions() == lastArgBinding.getDimensions())) {
// if this method is a varargs, and if the method is invoked using the varargs syntax
// (multiple arguments) and not an array
Iterator iterator= arguments.iterator();
// process the first arguments (no part of the variable argument)
for (int i= 0; i < paramCount - 1; i++) {
Expression argument= (Expression) iterator.next();
boolean storeRequired= checkAutoBoxing(argument.resolveTypeBinding(), parameterTypes[i]);
argument.accept(this);
if (storeRequired) {
storeInstruction();
}
}
// create a array of the remainder arguments
ITypeBinding varargsParameterType= parameterTypes[paramCount - 1];
ITypeBinding varargsElementType= varargsParameterType.getElementType();
push(new ArrayInitializerInstruction(getTypeSignature(varargsElementType), argCount - paramCount + 1, varargsParameterType.getDimensions(), fCounter));
while (iterator.hasNext()) {
Expression argument= (Expression) iterator.next();
boolean storeRequired= checkAutoBoxing(argument.resolveTypeBinding(), varargsElementType);
argument.accept(this);
if (storeRequired) {
storeInstruction();
}
}
storeInstruction();
} else {
Iterator iterator= arguments.iterator();
int i= 0;
while (iterator.hasNext()) {
Expression argument= (Expression) iterator.next();
boolean storeRequired= checkAutoBoxing(argument.resolveTypeBinding(), parameterTypes[i++]);
argument.accept(this);
if (storeRequired) {
storeInstruction();
}
}
}
return false;
}
/**
* @see ASTVisitor#visit(SwitchCase)
*/
public boolean visit(SwitchCase node) {
// never called
return false;
}
/**
* @see ASTVisitor#visit(SwitchStatement)
*/
public boolean visit(SwitchStatement node) {
if (!isActive()) {
return false;
}
push(new NoOp(fCounter));
int switchStart= fCounter;
node.getExpression().accept(this);
ArrayList statementsDefault= null;
Jump jumpDefault= null;
ArrayList jumpsStatements= new ArrayList();
ArrayList[] currentJumpsStatements= new ArrayList[] {new ArrayList(), null};
jumpsStatements.add(currentJumpsStatements);
for (Iterator iter= node.statements().iterator(); iter.hasNext();) {
Statement statement= (Statement) iter.next();
if (statement instanceof SwitchCase) {
SwitchCase switchCase= (SwitchCase) statement;
if (switchCase.isDefault()) {
jumpDefault= new Jump();
push(jumpDefault);
storeInstruction(); // jump
statementsDefault= new ArrayList();
} else {
if(switchCase.getExpression() instanceof StringLiteral) {
push(new SendMessage("equals", "(Ljava/lang/Object;)Z", 1, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
}
else {
push(new EqualEqualOperator(Instruction.T_int, Instruction.T_int, true, fCounter));
}
push(new Dup());
storeInstruction(); // dupe
switchCase.getExpression().accept(this);
storeInstruction(); // equal-equal
ConditionalJump condJump= new ConditionalJump(true);
push(condJump);
storeInstruction(); // conditional jump
if (currentJumpsStatements[1] != null) {
currentJumpsStatements= new ArrayList[] {new ArrayList(), null};
jumpsStatements.add(currentJumpsStatements);
}
currentJumpsStatements[0].add(condJump);
}
} else {
if (statementsDefault != null) {
statementsDefault.add(statement);
} else {
if (currentJumpsStatements[1] == null) {
currentJumpsStatements[1]= new ArrayList();
}
currentJumpsStatements[1].add(statement);
}
}
}
Jump jumpEnd= null;
if (jumpDefault == null) {
push(new Pop(0));
storeInstruction(); // pop
jumpEnd= new Jump();
push(jumpEnd);
storeInstruction(); // jump
}
for (Iterator iter= jumpsStatements.iterator(); iter.hasNext();) {
currentJumpsStatements= (ArrayList[]) iter.next();
for (Iterator iterator= currentJumpsStatements[0].iterator(); iterator.hasNext();) {
ConditionalJump condJump= (ConditionalJump) iterator.next();
condJump.setOffset((fCounter - fInstructions.indexOf(condJump)) - 1);
}
if (currentJumpsStatements[1] != null) {
push(new Pop(0));
storeInstruction(); // pop
for (Iterator iterator= currentJumpsStatements[1].iterator(); iterator.hasNext();) {
((Statement) iterator.next()).accept(this);
}
}
}
// default case
if (jumpDefault != null) {
jumpDefault.setOffset((fCounter - fInstructions.indexOf(jumpDefault)) - 1);
push(new Pop(0));
storeInstruction(); // pop
for (Iterator iterator= statementsDefault.iterator(); iterator.hasNext();) {
((Statement) iterator.next()).accept(this);
}
} else {
jumpEnd.setOffset((fCounter - fInstructions.indexOf(jumpEnd)) - 1);
}
// for each pending break or continue instruction which are related to
// this loop, set the offset of the corresponding jump.
String label= getLabel(node);
for (Iterator iter= fCompleteInstructions.iterator(); iter.hasNext();) {
CompleteInstruction instruction= (CompleteInstruction) iter.next();
Jump jumpInstruction= instruction.fInstruction;
int instructionAddress= fInstructions.indexOf(jumpInstruction);
if (instructionAddress > switchStart && (instruction.fLabel == null || instruction.fLabel.equals(label))) {
iter.remove();
if (instruction.fIsBreak) {
// jump to the instruction after the last instruction of the switch
jumpInstruction.setOffset((fCounter - instructionAddress) - 1);
}
}
}
return false;
}
/**
* @see ASTVisitor#visit(SynchronizedStatement)
*/
public boolean visit(SynchronizedStatement node) {
if (!isActive()) {
return false;
}
return true;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TagElement)
*/
public boolean visit(TagElement node) {
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TextElement)
*/
public boolean visit(TextElement node) {
return false;
}
/**
* @see ASTVisitor#visit(ThisExpression)
*/
public boolean visit(ThisExpression node) {
if (!isActive()) {
return false;
}
Name qualifier= node.getQualifier();
int enclosingLevel= 0;
if (qualifier != null) {
ITypeBinding binding = (ITypeBinding)resolveBinding(qualifier);
if (binding == null) {
return false;
}
enclosingLevel= getEnclosingLevel(node, binding);
}
push(new PushThis(enclosingLevel));
return false;
}
/**
* @see ASTVisitor#visit(ThrowStatement)
*/
public boolean visit(ThrowStatement node) {
if (!isActive()) {
return false;
}
push(new ThrowInstruction(fCounter));
return true;
}
/**
* @see ASTVisitor#visit(TryStatement)
*/
public boolean visit(TryStatement node) {
if (!isActive()) {
return false;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Try_statement_cannot_be_used_in_an_evaluation_expression_23);
return false;
}
/**
* @see ASTVisitor#visit(TypeDeclaration)
*/
public boolean visit(TypeDeclaration node) {
if (!isActive()) {
return true;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Type_declaration_cannot_be_used_in_an_evaluation_expression_24);
return false;
}
/**
* @see ASTVisitor#visit(TypeDeclarationStatement)
*/
public boolean visit(TypeDeclarationStatement node) {
if (!isActive()) {
return true;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Type_declaration_statement_cannot_be_used_in_an_evaluation_expression_25);
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TypeParameter)
*/
public boolean visit(TypeParameter node) {
return false;
}
/**
* @see ASTVisitor#visit(TypeLiteral)
*/
public boolean visit(TypeLiteral node) {
if (!isActive()) {
return false;
}
push(new PushClassLiteralValue(fCounter));
return true;
}
/**
* @see ASTVisitor#visit(VariableDeclarationExpression)
*/
public boolean visit(VariableDeclarationExpression node) {
/* if it is in the code to execute, return <code>false</code>,
* we don't use the standard accept order.
* Otherwise, return true. We want to search the code to execute
* in variable declarations (in case of inner classes).
*/
if (!isActive()) {
return true;
}
for (Iterator iter= node.fragments().iterator(); iter.hasNext();) {
((VariableDeclarationFragment) iter.next()).accept(this);
}
return false;
}
/**
* @see ASTVisitor#visit(VariableDeclarationFragment)
*/
public boolean visit(VariableDeclarationFragment node) {
/* if it is in the code to execute, return <code>false</code>,
* we don't use the standard accept order.
* Otherwise, return true. We want to search the code to execute
* in variable declarations (in case of inner classes).
*/
if (!isActive()) {
return true;
}
// get the type of the variable
ITypeBinding varTypeBinding;
ASTNode parent= node.getParent();
switch (parent.getNodeType()) {
case ASTNode.VARIABLE_DECLARATION_EXPRESSION:
varTypeBinding= resolveTypeBinding(((VariableDeclarationExpression)parent).getType());
break;
case ASTNode.VARIABLE_DECLARATION_STATEMENT:
varTypeBinding= resolveTypeBinding(((VariableDeclarationStatement)parent).getType());
break;
default:
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Error_in_type_declaration_statement);
return false;
}
if (varTypeBinding == null) {
return false;
}
int typeDimension= varTypeBinding.getDimensions();
ITypeBinding elementBinding = varTypeBinding;
if (typeDimension != 0) {
elementBinding= elementBinding.getElementType();
}
Expression initializer= node.getInitializer();
push(new LocalVariableCreation(node.getName().getIdentifier(), getTypeSignature(elementBinding), typeDimension, elementBinding.isPrimitive(), initializer != null, fCounter));
if (initializer != null) {
initializer.accept(this);
ITypeBinding expBindnig = initializer.resolveTypeBinding();
if (expBindnig != null) {
if (checkAutoBoxing(expBindnig, varTypeBinding)) {
storeInstruction();
}
}
}
return false;
}
/**
* @see ASTVisitor#visit(VariableDeclarationStatement)
*/
public boolean visit(VariableDeclarationStatement node) {
/* if it is in the code to execute, return <code>false</code>,
* we don't use the standard accept order.
* Otherwise, return true. We want to search the code to execute
* in variable declarations (in case of inner classes).
*/
if (!isActive()) {
return true;
}
for (Iterator iter= node.fragments().iterator(); iter.hasNext();) {
((VariableDeclarationFragment) iter.next()).accept(this);
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.WildcardType)
*/
public boolean visit(WildcardType node) {
// we shouldn't have to do anything
return false;
}
/**
* @see ASTVisitor#visit(WhileStatement)
*/
public boolean visit(WhileStatement node) {
if (!isActive()) {
return false;
}
push(new NoOp(fCounter));
return true;
}
//--------------------------
private int getTypeId(Expression expression) {
ITypeBinding typeBinding = expression.resolveTypeBinding();
if (typeBinding == null) {
return Instruction.T_undefined;
}
String typeName = typeBinding.getQualifiedName();
if (typeBinding.isPrimitive()) {
return getPrimitiveTypeId(typeName);
} else if ("java.lang.String".equals(typeName)){ //$NON-NLS-1$
return Instruction.T_String;
} else {
return Instruction.T_Object;
}
}
private int getUnBoxedTypeId(Expression expression) {
ITypeBinding typeBinding = expression.resolveTypeBinding();
if (typeBinding == null) {
return Instruction.T_undefined;
}
String typeName = typeBinding.getQualifiedName();
if (typeBinding.isPrimitive()) {
return getPrimitiveTypeId(typeName);
} else if ("java.lang.String".equals(typeName)){ //$NON-NLS-1$
return Instruction.T_String;
} else {
// un-boxing
if ("java.lang.Integer".equals(typeName)) { //$NON-NLS-1$
return Instruction.T_int;
} else if ("java.lang.Character".equals(typeName)) { //$NON-NLS-1$
return Instruction.T_char;
} else if ("java.lang.Byte".equals(typeName)) { //$NON-NLS-1$
return Instruction.T_byte;
} else if ("java.lang.Short".equals(typeName)) { //$NON-NLS-1$
return Instruction.T_short;
} else if ("java.lang.Long".equals(typeName)) { //$NON-NLS-1$
return Instruction.T_long;
} else if ("java.lang.Float".equals(typeName)) { //$NON-NLS-1$
return Instruction.T_float;
} else if ("java.lang.Double".equals(typeName)) { //$NON-NLS-1$
return Instruction.T_double;
} else if ("java.lang.Boolean".equals(typeName)) { //$NON-NLS-1$
return Instruction.T_boolean;
}
return Instruction.T_Object;
}
}
private int getTypeId(Type type) {
if (type.isPrimitiveType()) {
return getPrimitiveTypeId(((PrimitiveType)type).getPrimitiveTypeCode().toString());
} else if (type.isSimpleType()) {
SimpleType simpleType = (SimpleType) type;
if ("java.lang.String".equals(simpleType.getName().getFullyQualifiedName())){ //$NON-NLS-1$
return Instruction.T_String;
}
return Instruction.T_Object;
} else if (type.isArrayType()) {
return Instruction.T_Object;
} else {
return Instruction.T_undefined;
}
}
/**
* Returns the method signature given the binding and the enclosing type signature (if there is one)
* @param methodBinding the binding to get the signature for
* @param enclosingTypeSignature the enclosing type signature or <code>null</code>
* @return the method signature for the given binding and enclosing type signature
*/
private String getMethodSignature(IMethodBinding methodBinding, String enclosingTypeSignature) {
methodBinding= methodBinding.getMethodDeclaration();
ITypeBinding[] parameterTypes = methodBinding.getParameterTypes();
int offset = 0;
int argCount;
String[] parameterSignatures;
if (enclosingTypeSignature == null) {
argCount= parameterTypes.length;
parameterSignatures= new String[argCount];
} else {
offset = 1;
argCount= parameterTypes.length + 1;
parameterSignatures= new String[argCount];
parameterSignatures[0]= enclosingTypeSignature;
}
for (int i = 0; i < parameterTypes.length; i++) {
parameterSignatures[i+offset]= getTypeSignature(parameterTypes[i]);
}
String signature= Signature.createMethodSignature(parameterSignatures, getTypeSignature(methodBinding.getReturnType()));
return signature;
}
private int getPrimitiveTypeId(String typeName) {
switch (typeName.charAt(0)) {
case 'b': // byte or boolean
switch (typeName.charAt(1)) {
case 'o': // boolean;
return Instruction.T_boolean;
case 'y': // byte
return Instruction.T_byte;
}
break;
case 'c': // char
return Instruction.T_char;
case 'd': // double
return Instruction.T_double;
case 'f': // float
return Instruction.T_float;
case 'i': // int
return Instruction.T_int;
case 'l': // long
return Instruction.T_long;
case 'n':
return Instruction.T_null;
case 's': // short
return Instruction.T_short;
case 'v': // void
return Instruction.T_void;
}
return Instruction.T_undefined;
}
/**
* Resolves and returns the type binding from the given expression reporting an error
* if the binding is <code>null</code>.
*
* @param expression expression to resolve type binding for
* @return type binding or <code>null</code> if not available
*/
private ITypeBinding resolveTypeBinding(Expression expression) {
ITypeBinding typeBinding = expression.resolveTypeBinding();
if (typeBinding == null) {
setHasError(true);
addErrorMessage(MessageFormat.format(EvaluationEngineMessages.ASTInstructionCompiler_3, new String[]{expression.toString()}));
}
return typeBinding;
}
/**
* Resolves and returns the type binding for the give type reporting an error
* if the binding is <code>null</code>.
*
* @param type type to resolve binding for
* @return type binding or <code>null</code> if not available
*/
private ITypeBinding resolveTypeBinding(Type type) {
ITypeBinding typeBinding = type.resolveBinding();
if (typeBinding == null) {
setHasError(true);
addErrorMessage(MessageFormat.format(EvaluationEngineMessages.ASTInstructionCompiler_3, new String[]{type.toString()}));
}
return typeBinding;
}
/**
* Resolves and returns the binding for the given name reporting an error
* if the binding is <code>null</code>.
*
* @param name name to resolve binding for
* @return binding or <code>null</code> if not available
*/
private IBinding resolveBinding(Name name) {
IBinding binding = name.resolveBinding();
if (binding == null) {
setHasError(true);
addErrorMessage(MessageFormat.format(EvaluationEngineMessages.ASTInstructionCompiler_5, new String[]{name.getFullyQualifiedName()}));
}
return binding;
}
/**
* Resolves and returns the type binding for the given name reporting an error
* if the binding is <code>null</code>.
*
* @param name name to resolve type binding for
* @return type binding or <code>null</code> if not available
*/
private ITypeBinding resolveTypeBinding(Name name) {
ITypeBinding typeBinding = name.resolveTypeBinding();
if (typeBinding == null) {
setHasError(true);
addErrorMessage(MessageFormat.format(EvaluationEngineMessages.ASTInstructionCompiler_3, new String[]{name.getFullyQualifiedName()}));
}
return typeBinding;
}
}