/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.internal.gosu.ir.compiler.verifier;
import gw.lang.ir.IRClass;
import gw.lang.ir.IRType;
import gw.lang.ir.IRStatement;
import gw.lang.ir.IRExpression;
import gw.lang.ir.IRElement;
import gw.lang.ir.IRTypeConstants;
import gw.lang.ir.expression.IRArithmeticExpression;
import gw.lang.ir.expression.IRArrayLengthExpression;
import gw.lang.ir.expression.IRArrayLoadExpression;
import gw.lang.ir.expression.IRBooleanLiteral;
import gw.lang.ir.expression.IRCharacterLiteral;
import gw.lang.ir.expression.IRIdentifier;
import gw.lang.ir.expression.IRFieldGetExpression;
import gw.lang.ir.expression.IREqualityExpression;
import gw.lang.ir.expression.IRCompositeExpression;
import gw.lang.ir.expression.IRMethodCallExpression;
import gw.lang.ir.expression.IRNullLiteral;
import gw.lang.ir.expression.IRPrimitiveTypeConversion;
import gw.lang.ir.expression.IRTernaryExpression;
import gw.lang.ir.expression.IRNumericLiteral;
import gw.lang.ir.expression.IRStringLiteralExpression;
import gw.lang.ir.expression.IRNewArrayExpression;
import gw.lang.ir.expression.IRCastExpression;
import gw.lang.ir.expression.IRNewExpression;
import gw.lang.ir.expression.IRRelationalExpression;
import gw.lang.ir.expression.IRNegationExpression;
import gw.lang.ir.expression.IRConditionalOrExpression;
import gw.lang.ir.expression.IRConditionalAndExpression;
import gw.lang.ir.expression.IRClassLiteral;
import gw.lang.ir.expression.IRNotExpression;
import gw.lang.ir.expression.IRInstanceOfExpression;
import gw.lang.ir.expression.IRNewMultiDimensionalArrayExpression;
import gw.lang.ir.expression.IRNoOpExpression;
import gw.lang.ir.statement.IREvalStatement;
import gw.lang.ir.statement.IRFieldDecl;
import gw.lang.ir.statement.IRMethodStatement;
import gw.lang.ir.statement.IRMethodCallStatement;
import gw.lang.ir.statement.IRIfStatement;
import gw.lang.ir.statement.IRFieldSetStatement;
import gw.lang.ir.statement.IRAssignmentStatement;
import gw.lang.ir.statement.IRNoOpStatement;
import gw.lang.ir.statement.IRReturnStatement;
import gw.lang.ir.statement.IRStatementList;
import gw.lang.ir.statement.IRArrayStoreStatement;
import gw.lang.ir.statement.IRBreakStatement;
import gw.lang.ir.statement.IRThrowStatement;
import gw.lang.ir.statement.IRTryCatchFinallyStatement;
import gw.lang.ir.statement.IRCatchClause;
import gw.lang.ir.statement.IRSyntheticStatement;
import gw.lang.ir.statement.IRCaseClause;
import gw.lang.ir.statement.IRContinueStatement;
import gw.lang.ir.statement.IRForEachStatement;
import gw.lang.ir.statement.IRWhileStatement;
import gw.lang.ir.statement.IRDoWhileStatement;
import gw.lang.ir.statement.IRMonitorLockAcquireStatement;
import gw.lang.ir.statement.IRMonitorLockReleaseStatement;
import gw.lang.ir.statement.IRSwitchStatement;
import gw.internal.gosu.ir.compiler.tree.IRTreeCompiler;
import gw.internal.gosu.ir.compiler.bytecode.IRClassCompiler;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import java.util.HashSet;
public class IRTreeVerifier {
private List<String> _errors = new ArrayList<String>();
private IRMethodStatement _enclosingMethodStatement;
private IRClass _enclosingClass;
public IRTreeVerifier() {
}
public List<String> getErrors() {
return _errors;
}
public void printErrors() {
if (_errors.isEmpty()) {
System.out.println("No errors detected");
} else {
for (String error : _errors) {
System.out.println("***ERROR: " + error);
}
}
}
public void verifyClassStatement(IRClass irClass) {
_enclosingClass = irClass;
for (IRFieldDecl fieldDecl : irClass.getFields()) {
verifyIRFieldDecl(fieldDecl);
}
Set<String> methodSignatures = new HashSet<String>();
for (IRMethodStatement methodStatement : irClass.getMethods()) {
String signature = methodStatement.getName() + IRClassCompiler.getMethodDescriptor(methodStatement);
if (methodSignatures.add(signature)) {
verifyIRMethodStatement(methodStatement);
} else {
error("Duplicate methods found with signature " + signature, methodStatement);
}
}
}
private void verifyIRElement(IRElement element) {
if (element instanceof IRStatement) {
verifyIRStatement((IRStatement) element);
} else {
verifyIRExpression((IRExpression) element);
}
}
private void verifyIRStatement(IRStatement statement) {
if (statement == null) {
return;
}
verifyParentIsSet( statement );
if (statement instanceof IRAssignmentStatement) {
verifyIRAssignmentStatement((IRAssignmentStatement) statement);
} else if (statement instanceof IRFieldDecl) {
verifyIRFieldDecl((IRFieldDecl) statement);
} else if (statement instanceof IRFieldSetStatement) {
verifyIRFieldSetStatement((IRFieldSetStatement) statement);
} else if (statement instanceof IRIfStatement) {
verifyIRIfStatement((IRIfStatement) statement);
} else if (statement instanceof IRMethodCallStatement) {
verifyIRMethodCallStatement((IRMethodCallStatement) statement);
} else if (statement instanceof IRMethodStatement) {
verifyIRMethodStatement((IRMethodStatement) statement);
} else if (statement instanceof IRNoOpStatement) {
verifyIRNoOpStatement((IRNoOpStatement) statement);
} else if (statement instanceof IRReturnStatement) {
verifyIRReturnStatement((IRReturnStatement) statement);
} else if (statement instanceof IRStatementList) {
verifyIRStatementList((IRStatementList) statement);
} else if (statement instanceof IRArrayStoreStatement) {
verifyIRArrayStoreStatement((IRArrayStoreStatement) statement);
} else if (statement instanceof IRThrowStatement) {
verifyIRThrowStatement((IRThrowStatement) statement);
} else if (statement instanceof IRTryCatchFinallyStatement) {
verifyIRTryCatchFinallyStatement((IRTryCatchFinallyStatement) statement);
} else if (statement instanceof IRSyntheticStatement) {
verifyIRSyntheticStatement((IRSyntheticStatement) statement);
} else if (statement instanceof IRForEachStatement) {
verifyIRForEachStatement((IRForEachStatement) statement);
} else if (statement instanceof IRBreakStatement) {
verifyIRBreakStatement((IRBreakStatement) statement);
} else if (statement instanceof IRContinueStatement) {
verifyIRContinueStatement((IRContinueStatement) statement);
} else if (statement instanceof IRWhileStatement) {
verifyIRWhileStatement((IRWhileStatement) statement);
} else if (statement instanceof IRDoWhileStatement) {
verifyIRDoWhileStatement((IRDoWhileStatement) statement);
} else if (statement instanceof IRMonitorLockAcquireStatement) {
verifyIRIRMonitorLockAcquireStatement((IRMonitorLockAcquireStatement) statement);
} else if (statement instanceof IRMonitorLockReleaseStatement ) {
verifyIRIRMonitorLockReleaseStatement((IRMonitorLockReleaseStatement) statement);
} else if (statement instanceof IRSwitchStatement) {
verifyIRSwitchStatement((IRSwitchStatement) statement);
} else if (statement instanceof IREvalStatement ) {
verifyIREvalStatement((IREvalStatement) statement);
} else {
throw new IllegalArgumentException("Unrecognized statement of type " + statement.getClass());
}
}
private void verifyIRSwitchStatement(IRSwitchStatement irSwitchStatement) {
verifyIRStatement(irSwitchStatement.getInit());
for (IRCaseClause caseClause : irSwitchStatement.getCases()) {
verifyIRExpression( caseClause.getCondition() );
for (IRStatement caseStatement : caseClause.getStatements() ) {
verifyIRStatement( caseStatement );
}
}
for (IRStatement defaultStatement : irSwitchStatement.getDefaultStatements() ) {
verifyIRStatement( defaultStatement );
}
}
private void verifyIRIRMonitorLockAcquireStatement( IRMonitorLockAcquireStatement irMonitorLockAcquireStatement ) {
}
private void verifyIRIRMonitorLockReleaseStatement( IRMonitorLockReleaseStatement irMonitorLockReleaseStatement ) {
}
private void verifyIRDoWhileStatement(IRDoWhileStatement irDoWhileLoopStatement) {
verifyIRExpression( irDoWhileLoopStatement.getLoopTest() );
verifyIRStatement( irDoWhileLoopStatement.getBody() );
}
private void verifyIRWhileStatement(IRWhileStatement irWhileLoopStatement) {
verifyIRExpression( irWhileLoopStatement.getLoopTest() );
verifyIRStatement( irWhileLoopStatement.getBody() );
}
private void verifyIRContinueStatement(IRContinueStatement irContinueStatement) {
// Nothing
}
private void verifyIRBreakStatement(IRBreakStatement irBreakStatement) {
// Nothing
}
private void verifyIREvalStatement( IREvalStatement evalStmt ) {
verifyIRExpression( evalStmt.getExpression() );
}
private void verifyIRForEachStatement(IRForEachStatement irForLoopStatement) {
for (IRStatement s : irForLoopStatement.getInitializers()) {
verifyIRStatement( s );
}
verifyIRExpression( irForLoopStatement.getLoopTest() );
for (IRStatement s : irForLoopStatement.getIncrementors()) {
verifyIRStatement( s );
}
verifyIRStatement( irForLoopStatement.getBody() );
}
private void verifyIRSyntheticStatement(IRSyntheticStatement irSyntheticStatement) {
verifyIRExpression(irSyntheticStatement.getExpression());
}
private void verifyIRTryCatchFinallyStatement(IRTryCatchFinallyStatement irTryCatchFinallyStatement) {
verifyIRStatement( irTryCatchFinallyStatement.getTryBody() );
for (IRCatchClause catchClause : irTryCatchFinallyStatement.getCatchStatements()) {
verifyIRStatement(catchClause.getBody());
}
if (irTryCatchFinallyStatement.getFinallyBody() != null) {
verifyIRStatement( irTryCatchFinallyStatement.getFinallyBody() );
}
}
private void verifyIRThrowStatement(IRThrowStatement irThrowStatement) {
verifyIRExpression( irThrowStatement.getException() );
}
private void verifyIRArrayStoreStatement(IRArrayStoreStatement irArrayStoreStatement) {
if (!verifyExpressionIsOfType( irArrayStoreStatement.getTarget().getType().getComponentType(), irArrayStoreStatement.getValue())) {
error("Attempting to store a value of type " + irArrayStoreStatement.getValue().getType().getName() + " in an array of type " + irArrayStoreStatement.getTarget().getType().getRelativeName(), irArrayStoreStatement);
}
verifyIRExpression( irArrayStoreStatement.getTarget() );
verifyIRExpression( irArrayStoreStatement.getIndex() );
verifyIRExpression( irArrayStoreStatement.getValue() );
}
private void verifyIRFieldSetStatement(IRFieldSetStatement irFieldSetStatement) {
verifyIRExpression( irFieldSetStatement.getLhs() );
verifyIRExpression( irFieldSetStatement.getRhs() );
}
private void verifyIRIfStatement(IRIfStatement irIfStatement) {
verifyIRExpression( irIfStatement.getExpression() );
verifyIRStatement( irIfStatement.getIfStatement() );
verifyIRStatement( irIfStatement.getElseStatement() );
}
private void verifyIRMethodCallStatement(IRMethodCallStatement irMethodCallStatement) {
verifyIRExpression( irMethodCallStatement.getExpression() );
}
private void verifyIRNoOpStatement(IRNoOpStatement irNoOpStatement) {
}
private void verifyIRReturnStatement(IRReturnStatement irReturnStatement) {
if (_enclosingMethodStatement.getReturnType().isVoid()) {
if (irReturnStatement.getReturnValue() != null) {
error("Method " + _enclosingMethodStatement.getName() + " has a void return type, but a return statement returned a value", irReturnStatement);
}
} else if (irReturnStatement.getReturnValue() == null) {
error("Method " + _enclosingMethodStatement.getName() + " has a non-void return type, but a return statement has no value", irReturnStatement);
} else {
if (!verifyExpressionIsOfType(_enclosingMethodStatement.getReturnType(), irReturnStatement.getReturnValue())) {
error("Method " + _enclosingMethodStatement.getName() + " has a return type of " + _enclosingMethodStatement.getReturnType().getName() + " but a return statement has a value of type " + irReturnStatement.getReturnValue().getType().getName(), irReturnStatement);
}
}
verifyIRExpression( irReturnStatement.getReturnValue() );
}
private void verifyIRStatementList(IRStatementList irStatementList) {
for (IRStatement statement : irStatementList.getStatements()) {
verifyIRStatement(statement);
}
}
private void verifyIRAssignmentStatement(IRAssignmentStatement irAssignmentStatement) {
if (!verifyExpressionIsOfType( irAssignmentStatement.getSymbol().getType(), irAssignmentStatement.getValue())) {
error("Attempted to assign a value of type " + irAssignmentStatement.getValue().getType().getName() + " to a symbol of type " + irAssignmentStatement.getSymbol().getType().getName(), irAssignmentStatement);
}
verifyIRExpression( irAssignmentStatement.getValue() );
}
private void verifyIRExpression(IRExpression expression) {
if (expression == null) {
return;
}
verifyParentIsSet( expression );
if (expression instanceof IRArithmeticExpression) {
verifyIRAdditiveExpression((IRArithmeticExpression) expression);
} else if (expression instanceof IRArrayLoadExpression) {
verifyIRArrayLoadExpression((IRArrayLoadExpression) expression);
} else if (expression instanceof IRBooleanLiteral) {
verifyIRBooleanLiteral((IRBooleanLiteral) expression);
} else if (expression instanceof IRCompositeExpression) {
verifyIRCompositeExpression((IRCompositeExpression) expression);
} else if (expression instanceof IREqualityExpression) {
verifyIREqualityExpression((IREqualityExpression) expression);
} else if (expression instanceof IRFieldGetExpression) {
verifyIRFieldGetExpression((IRFieldGetExpression) expression);
} else if (expression instanceof IRIdentifier) {
verifyIRIdentifier((IRIdentifier) expression);
} else if (expression instanceof IRMethodCallExpression) {
verifyIRMethodCallExpression((IRMethodCallExpression) expression);
} else if (expression instanceof IRNullLiteral) {
verifyIRNullLiteral((IRNullLiteral) expression);
} else if (expression instanceof IRPrimitiveTypeConversion) {
verifyIRPrimitiveTypeConversion((IRPrimitiveTypeConversion) expression);
} else if (expression instanceof IRTernaryExpression) {
verifyIRTernaryExpression((IRTernaryExpression) expression);
} else if (expression instanceof IRNumericLiteral) {
verifyIRNumericLiteral((IRNumericLiteral) expression);
} else if (expression instanceof IRCharacterLiteral ) {
verifyIRCharacterLiteral((IRCharacterLiteral) expression);
} else if (expression instanceof IRStringLiteralExpression) {
verifyIRStringLiteralExpression((IRStringLiteralExpression) expression);
} else if (expression instanceof IRNewArrayExpression) {
verifyIRNewArrayExpression((IRNewArrayExpression) expression);
} else if (expression instanceof IRCastExpression) {
verifyIRCastExpression((IRCastExpression) expression);
} else if (expression instanceof IRNewExpression) {
verifyIRNewExpression((IRNewExpression) expression);
} else if (expression instanceof IRRelationalExpression) {
verifyIRRelationalExpression((IRRelationalExpression) expression);
} else if (expression instanceof IRNegationExpression) {
verifyIRNegationExpression((IRNegationExpression) expression);
} else if (expression instanceof IRConditionalOrExpression) {
verifyIRConditionalOrExpression((IRConditionalOrExpression) expression);
} else if (expression instanceof IRConditionalAndExpression) {
verifyIRConditionalAndExpression((IRConditionalAndExpression) expression);
} else if (expression instanceof IRArrayLengthExpression) {
verifyIRArrayLengthExpression((IRArrayLengthExpression) expression);
} else if (expression instanceof IRClassLiteral) {
verifyIRClassLiteral((IRClassLiteral) expression);
} else if (expression instanceof IRNotExpression) {
verifyIRNotExpression((IRNotExpression) expression);
} else if (expression instanceof IRInstanceOfExpression) {
verifyIRInstanceOfExpression((IRInstanceOfExpression) expression);
} else if (expression instanceof IRNewMultiDimensionalArrayExpression) {
verifyIRNewMultiDimensionalArrayExpression((IRNewMultiDimensionalArrayExpression) expression);
} else if (expression instanceof IRNoOpExpression) {
// Do nothing
} else {
throw new IllegalArgumentException("Unrecognized expression of type " + expression.getClass());
}
}
private void verifyIRNewMultiDimensionalArrayExpression(IRNewMultiDimensionalArrayExpression irNewMultiDimensionalArrayExpression) {
for (IRExpression irExpression : irNewMultiDimensionalArrayExpression.getSizeExpressions()) {
verifyIRExpression(irExpression);
}
}
private void verifyIRInstanceOfExpression(IRInstanceOfExpression irInstanceOfExpression) {
verifyIRExpression(irInstanceOfExpression.getRoot());
}
private void verifyIRNotExpression(IRNotExpression irNotExpression) {
verifyIRExpression(irNotExpression.getRoot());
}
private void verifyIRClassLiteral(IRClassLiteral irClassLiteral) {
// Nothing for now
}
private void verifyIRArrayLengthExpression(IRArrayLengthExpression irArrayLengthExpression) {
if (!irArrayLengthExpression.getRoot().getType().isArray()) {
error("Array length expression root must be an array type, but was " + irArrayLengthExpression.getRoot().getType().getName(), irArrayLengthExpression);
}
verifyIRExpression(irArrayLengthExpression.getRoot());
}
private void verifyIRConditionalAndExpression(IRConditionalAndExpression irConditionalAndExpression) {
verifyIRExpression(irConditionalAndExpression.getLhs());
verifyIRExpression(irConditionalAndExpression.getRhs());
}
private void verifyIRConditionalOrExpression(IRConditionalOrExpression irConditionalOrExpression) {
verifyIRExpression(irConditionalOrExpression.getLhs());
verifyIRExpression(irConditionalOrExpression.getRhs());
}
private void verifyIRNegationExpression(IRNegationExpression irNegationExpression) {
verifyIRExpression(irNegationExpression.getRoot());
}
private void verifyIRRelationalExpression(IRRelationalExpression irRelationalExpression) {
verifyIRExpression( irRelationalExpression.getLhs() );
verifyIRExpression( irRelationalExpression.getRhs() );
}
private void verifyIRNewExpression(IRNewExpression irNewExpression) {
verifyTypeAgreement(irNewExpression.getParameterTypes(), irNewExpression.getArgs(), irNewExpression);
for (IRExpression arg : irNewExpression.getArgs()) {
verifyIRExpression(arg);
}
}
private void verifyIRCastExpression(IRCastExpression irCastExpression) {
verifyIRExpression( irCastExpression.getRoot() );
}
private void verifyIRNewArrayExpression(IRNewArrayExpression irNewArrayExpression) {
verifyIRExpression( irNewArrayExpression.getSizeExpression() );
}
private void verifyIRStringLiteralExpression(IRStringLiteralExpression irStringLiteralExpression) {
}
private void verifyIRNumericLiteral(IRNumericLiteral irNumericLiteral) {
}
private void verifyIRCharacterLiteral(IRCharacterLiteral irNumericLiteral) {
}
private void verifyIRAdditiveExpression(IRArithmeticExpression irAdditiveExpression) {
verifyIRExpression( irAdditiveExpression.getLhs() );
verifyIRExpression( irAdditiveExpression.getRhs() );
}
private void verifyIRArrayLoadExpression(IRArrayLoadExpression irArrayLoadExpression) {
verifyIRExpression( irArrayLoadExpression.getRoot() );
verifyIRExpression( irArrayLoadExpression.getIndex() );
}
private void verifyIRBooleanLiteral(IRBooleanLiteral irBooleanLiteral) {
}
private void verifyIRCompositeExpression(IRCompositeExpression irCompositeExpression) {
for (int i = 0; i < irCompositeExpression.getElements().size(); i++) {
IRElement element = irCompositeExpression.getElements().get(i);
if (i < irCompositeExpression.getElements().size() - 1) {
if (!(element instanceof IRStatement)) {
error("Composite does not consist of statements followed by a single expression: " + printElement( irCompositeExpression ), irCompositeExpression );
}
} else {
if (!(element instanceof IRExpression)) {
error("Composite does not consist of statements followed by a single expression: " + printElement( irCompositeExpression ), irCompositeExpression );
}
}
}
for (IRElement element : irCompositeExpression.getElements()) {
verifyIRElement(element);
}
}
private void verifyIREqualityExpression(IREqualityExpression irEqualityExpression) {
// TODO - Verify the types are the same?
verifyIRElement( irEqualityExpression.getLhs() );
verifyIRElement( irEqualityExpression.getRhs() );
}
private void verifyIRFieldGetExpression(IRFieldGetExpression irFieldGetExpression) {
verifyIRElement( irFieldGetExpression.getLhs() );
}
private void verifyIRIdentifier(IRIdentifier irIdentifier) {
}
private void verifyIRMethodCallExpression(IRMethodCallExpression irMethodCallExpression) {
verifyTypeAgreement(irMethodCallExpression.getParameterTypes(), irMethodCallExpression.getArgs(), irMethodCallExpression);
if (irMethodCallExpression.getRoot() != null && !verifyExpressionIsOfType(irMethodCallExpression.getOwnersType(), irMethodCallExpression.getRoot())) {
error("Owner type mismatch. Owner is of type " + irMethodCallExpression.getOwnersType().getName() + " but root expression is of type " + irMethodCallExpression.getRoot().getType().getName() + ". Error is in " + printElement(irMethodCallExpression), irMethodCallExpression);
}
verifyIRExpression( irMethodCallExpression.getRoot() );
for (IRExpression arg : irMethodCallExpression.getArgs()) {
verifyIRExpression(arg);
}
}
private void verifyIRNullLiteral(IRNullLiteral irNullLiteral) {
}
private void verifyIRPrimitiveTypeConversion(IRPrimitiveTypeConversion irPrimitiveTypeConversion) {
verifyIRExpression( irPrimitiveTypeConversion.getRoot() );
}
private void verifyIRTernaryExpression(IRTernaryExpression irTernaryExpression) {
if (!irTernaryExpression.getTest().getType().equals(IRTypeConstants.pBOOLEAN())) {
error("Type mismatch for ternary test. Must be of type boolean, but was of type " + irTernaryExpression.getTest().getType().getName(), irTernaryExpression);
}
if (!verifyExpressionIsOfType(irTernaryExpression.getType(), irTernaryExpression.getTrueValue())) {
error("Type mismatch in ternary expression. Overall expression is of type " + irTernaryExpression.getType().getName() + " but true expression is of type " + irTernaryExpression.getTrueValue().getType().getName(), irTernaryExpression);
}
if (!verifyExpressionIsOfType(irTernaryExpression.getType(), irTernaryExpression.getFalseValue())) {
error("Type mismatch in ternary expression. Overall expression is of type " + irTernaryExpression.getType().getName() + " but false expression is of type " + irTernaryExpression.getTrueValue().getType().getName(), irTernaryExpression);
}
verifyIRExpression( irTernaryExpression.getTest() );
verifyIRExpression( irTernaryExpression.getTrueValue() );
verifyIRExpression( irTernaryExpression.getFalseValue() );
}
private void verifyIRFieldDecl(IRFieldDecl fieldDecl) {
}
private void verifyIRMethodStatement(IRMethodStatement methodStatement) {
_enclosingMethodStatement = methodStatement;
try {
verifyIRStatement(methodStatement.getMethodBody());
} finally {
_enclosingMethodStatement = null;
}
}
private String printElement( IRElement element ) {
IRTreeCompiler compiler = new IRTreeCompiler();
compiler.compileIRElement(element, 0);
return compiler.getOutput().toString();
}
private void error( String message, IRElement element ) {
String enclosingStatement = getEnclosingStatement(element);
if (enclosingStatement != null) {
message = "Error found near " + enclosingStatement + "\n" + message;
} else if (_enclosingMethodStatement != null) {
message = "Error found in " + _enclosingClass.getName() + "." + _enclosingMethodStatement.getName() + "\n" + message;
} else if (_enclosingClass != null) {
message = "Error found in " + _enclosingClass.getName() + "\n" + message;
}
_errors.add( message );
}
private void verifyTypeAgreement( List<IRType> parameterTypes, List<IRExpression> arguments, IRElement element) {
if (parameterTypes.size() != arguments.size()) {
error("Argument number mismatch in " + printElement( element ), element );
} else {
for (int i = 0; i < parameterTypes.size(); i++) {
IRType paramType = parameterTypes.get(i);
IRExpression argument = arguments.get(i);
if (!verifyExpressionIsOfType(paramType, argument)) {
error("Argument type mismatch. Parameter is of type " + paramType.getName() + " but argument is of type " + argument.getType().getName() + ". Error is in " + printElement(element), element);
}
}
}
}
private void verifyParentIsSet( IRElement element ) {
if ( element.getParent() == null) {
error("Null parent for element " + printElement( element ), element);
}
}
private boolean verifyExpressionIsOfType(IRType type, IRExpression expression) {
boolean match = (expression instanceof IRNullLiteral && !type.isPrimitive()) ||
type.isAssignableFrom(expression.getType()) ||
(isIntType( type ) && isIntType( expression.getType() ) ); // Allow assignment between types that map to the same thing in bytecode
// Right now we sometimes have multiple casts, so if we've got a cast expression
// and it doesn't match, try unwrapping it
if (!match && expression instanceof IRCastExpression) {
return verifyExpressionIsOfType( type, ((IRCastExpression) expression).getRoot());
} else {
return match;
}
}
// Short, char, byte and int are all the same thing in bytecode and can be assigned
private boolean isIntType( IRType type ) {
return type.isShort() || type.isChar() || type.isInt() || type.isByte();
}
private String getEnclosingStatement( IRElement originalElement ) {
IRElement element = originalElement;
while (element != null) {
if (element instanceof IRStatement) {
IRStatement statement = (IRStatement) element;
if (statement.getLineNumber() != -1 && statement.getOriginalSourceStatement() != null) {
return statement.getOriginalSourceStatement();
}
}
element = element.getParent();
}
return null;
}
}