00001 package edu.ksu.cis.bandera.specification.assertion.ast;
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 import ca.mcgill.sable.soot.jimple.*;
00036 import edu.ksu.cis.bandera.annotation.*;
00037 import edu.ksu.cis.bandera.specification.assertion.datastructure.*;
00038 import edu.ksu.cis.bandera.specification.assertion.exception.*;
00039 import edu.ksu.cis.bandera.jjjc.*;
00040 import edu.ksu.cis.bandera.jjjc.analysis.*;
00041 import edu.ksu.cis.bandera.jjjc.util.*;
00042 import edu.ksu.cis.bandera.jjjc.node.*;
00043 import edu.ksu.cis.bandera.jjjc.symboltable.Package;
00044 import edu.ksu.cis.bandera.jjjc.symboltable.*;
00045 import java.util.*;
00046 public class TypeChecker extends DepthFirstAdapter {
00047 private SymbolTable symbolTable;
00048 private Vector usedTypeNames = new Vector();
00049 private Vector exceptions = new Vector();
00050 private ClassOrInterfaceType type;
00051 private Type currentType;
00052 private LabeledStmtAnnotation currentAnnotation;
00053 private Annotation annotation;
00054 boolean isStatic;
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132 public TypeChecker(SymbolTable symbolTable, ClassOrInterfaceType type, Annotation annotation, boolean isStatic) {
00133 this.symbolTable = symbolTable;
00134 this.type = type;
00135 if (annotation instanceof LabeledStmtAnnotation) {
00136 currentAnnotation = (LabeledStmtAnnotation) annotation;
00137 this.annotation = CompilationManager.getAnnotationManager().getMethodAnnotationContainingAnnotation(annotation);
00138 } else {
00139 this.annotation = annotation;
00140 }
00141 }
00142
00143
00144
00145
00146
00147 private PExp buildFieldAccess(AQualifiedName name) {
00148 PExp exp;
00149 if (name.getName() instanceof AQualifiedName) {
00150 exp = buildFieldAccess((AQualifiedName) name.getName());
00151 } else {
00152 exp = buildFieldAccess((ASimpleName) name.getName());
00153 }
00154
00155 return new AFieldAccessExp(new APrimaryFieldAccess(exp, new TDot(), name.getId()));
00156 }
00157
00158
00159
00160
00161
00162 private PExp buildFieldAccess(ASimpleName name) {
00163 return new ANameExp(name);
00164 }
00165
00166
00167
00168
00169
00170
00171 private PExp buildFieldAccess(PExp typeExp, String name) {
00172 if ("".equals(name.trim())) return typeExp;
00173 for (StringTokenizer tokenizer = new StringTokenizer(name, "."); tokenizer.hasMoreTokens();) {
00174 String token = (String) tokenizer.nextToken();
00175 if (currentType instanceof ClassOrInterfaceType) {
00176 ClassOrInterfaceType type = (ClassOrInterfaceType) currentType;
00177 try {
00178 currentType = type.getField(new Name(token)).getType();
00179 } catch (Exception e) {
00180 exceptions.add(e);
00181 currentType = VoidType.TYPE;
00182 }
00183 }
00184 typeExp = new AFieldAccessExp(new APrimaryFieldAccess(typeExp, new TDot(), new TId(token)));
00185 }
00186 return typeExp;
00187 }
00188
00189
00190
00191
00192 public void caseAArrayInitializer(AArrayInitializer node) {
00193 try {
00194 ArrayType at = (ArrayType) currentType;
00195 currentType = new ArrayType(at.baseType, at.nDimensions - 1);
00196
00197 Object temp[] = node.getVariableInitializer().toArray();
00198 for (int i = 0; i < temp.length; i++) {
00199 ((PVariableInitializer) temp[i]).apply(this);
00200 }
00201 } catch (Exception e) {
00202 exceptions.add(new TypeException("Type mismatch in array initializer"));
00203 }
00204 }
00205
00206
00207
00208
00209 public void caseAAssignmentExp(AAssignmentExp node) {
00210 String op = node.getAssignmentOperator().toString().trim();
00211 if ("=".equals(op)) {
00212 node.getLeftHandSide().apply(this);
00213 Type lhsType = currentType;
00214 node.getExp().apply(this);
00215 if (!(currentType.isValidIdentityConversion(lhsType) || currentType.isValidWideningConversion(lhsType))) {
00216 exceptions.add(new TypeException("Type mismatch in assignment operation"));
00217 }
00218 currentType = lhsType;
00219 } else {
00220 node.getLeftHandSide().apply(this);
00221 String s = currentType.toString();
00222 PName name = null;
00223 if ("java.lang.String".equals(s)) {
00224 name = new AQualifiedName(new AQualifiedName(new ASimpleName(new TId("java")), new TDot(), new TId("lang")), new TDot(), new TId("lang"));
00225 } else if ("boolean".equals(s)) {
00226 name = new ASimpleName(new TId("boolean"));
00227 } else if ("byte".equals(s)) {
00228 name = new ASimpleName(new TId("byte"));
00229 } else if ("short".equals(s)) {
00230 name = new ASimpleName(new TId("short"));
00231 } else if ("char".equals(s)) {
00232 name = new ASimpleName(new TId("char"));
00233 } else if ("int".equals(s)) {
00234 name = new ASimpleName(new TId("int"));
00235 } else if ("long".equals(s)) {
00236 name = new ASimpleName(new TId("long"));
00237 } else if ("float".equals(s)) {
00238 name = new ASimpleName(new TId("float"));
00239 } else if ("double".equals(s)) {
00240 name = new ASimpleName(new TId("double"));
00241 } else {
00242 currentType = VoidType.TYPE;
00243 exceptions.add(new TypeException("Type mismatch for assignment operator " + op));
00244 return;
00245 }
00246 PBinaryOperator binop;
00247 if ("+=".equals(op)) {
00248 binop = new APlusBinaryOperator();
00249 } else if ("-=".equals(op)) {
00250 binop = new AMinusBinaryOperator();
00251 } else if ("*=".equals(op)) {
00252 binop = new AStarBinaryOperator();
00253 } else if ("/=".equals(op)) {
00254 binop = new ADivBinaryOperator();
00255 } else if ("%=".equals(op)) {
00256 binop = new AModBinaryOperator();
00257 } else if ("<<=".equals(op)) {
00258 binop = new AShiftLeftBinaryOperator();
00259 } else if (">>=".equals(op)) {
00260 binop = new ASignedShiftRightBinaryOperator();
00261 } else if ("<<<=".equals(op)) {
00262 binop = new AUnsignedShiftRightBinaryOperator();
00263 } else if ("&=".equals(op)) {
00264 binop = new ABitAndBinaryOperator();
00265 } else if ("|=".equals(op)) {
00266 binop = new ABitOrBinaryOperator();
00267 } else if ("^=".equals(op)) {
00268 binop = new ABitXorBinaryOperator();
00269 } else {
00270 currentType = VoidType.TYPE;
00271 exceptions.add(new TypeException("Unknown operator " + op));
00272 return;
00273 }
00274
00275 PExp exp1;
00276
00277 if (node.getLeftHandSide() instanceof AFieldAccessLeftHandSide) {
00278 exp1 = new AFieldAccessExp((PFieldAccess) ((AFieldAccessLeftHandSide) node.getLeftHandSide()).getFieldAccess().clone());
00279 } else if (node.getLeftHandSide() instanceof AArrayAccessLeftHandSide) {
00280 exp1 = new AArrayAccessExp((PArrayAccess) ((AArrayAccessLeftHandSide) node.getLeftHandSide()).getArrayAccess().clone());
00281 } else {
00282 exp1 = new ANameExp((PName) ((ANameLeftHandSide) node.getLeftHandSide()).getName().clone());
00283 }
00284
00285 new AAssignmentExp((PLeftHandSide) node.getLeftHandSide().clone(), new AAssignAssignmentOperator(new TAssign()),
00286 new AExpCastExp(new TLPar(), new ANameExp(name), new TRPar(), new ABinaryExp(exp1, binop, (PExp) node.getExp().clone()))).apply(this);
00287 }
00288 }
00289
00290
00291
00292
00293 public void caseABinaryExp(ABinaryExp node) {
00294 node.getFirst().apply(this);
00295 Type leftType = currentType;
00296 node.getSecond().apply(this);
00297 Type rightType = currentType;
00298
00299 PBinaryOperator binOp = node.getBinaryOperator();
00300 if ((binOp instanceof AAndBinaryOperator) || (binOp instanceof AOrBinaryOperator)) {
00301
00302 currentType = BooleanType.TYPE;
00303 if ((leftType != BooleanType.TYPE) || (rightType != BooleanType.TYPE)) {
00304 exceptions.add(new TypeException("Expecting boolean expression"));
00305 }
00306 } else if ((binOp instanceof ABitAndBinaryOperator) || (binOp instanceof ABitOrBinaryOperator)
00307 || (binOp instanceof ABitXorBinaryOperator)) {
00308
00309 currentType = IntType.TYPE;
00310 if ((leftType == BooleanType.TYPE) && (rightType == BooleanType.TYPE)) {
00311 currentType = BooleanType.TYPE;
00312 } else if (getIntegralType(leftType, rightType) != null) {
00313 currentType = getIntegralType(leftType, rightType);
00314 } else {
00315 exceptions.add(new TypeException("Type mismatch for binary operator " + binOp.toString().trim()));
00316 }
00317 } else if ((binOp instanceof APlusBinaryOperator) || (binOp instanceof AMinusBinaryOperator)
00318 || (binOp instanceof AStarBinaryOperator) || (binOp instanceof ADivBinaryOperator)
00319 || (binOp instanceof AModBinaryOperator)) {
00320
00321 currentType = IntType.TYPE;
00322 if (getNumericType(leftType, rightType) != null) {
00323 currentType = getNumericType(leftType, rightType);
00324 } else {
00325 exceptions.add(new TypeException("Type mismatch for binary operator " + binOp.toString().trim()));
00326 }
00327 } else if ((binOp instanceof AShiftLeftBinaryOperator) || (binOp instanceof ASignedShiftRightBinaryOperator)
00328 || (binOp instanceof AUnsignedShiftRightBinaryOperator)) {
00329
00330 currentType = IntType.TYPE;
00331 if (getIntegralType(leftType, rightType) != null) {
00332 currentType = getIntegralType(leftType, rightType);
00333 } else {
00334 exceptions.add(new TypeException("Type mismatch for binary operator " + binOp.toString().trim()));
00335 }
00336 } else if ((binOp instanceof ALtBinaryOperator) || (binOp instanceof ALteqBinaryOperator)
00337 || (binOp instanceof AGtBinaryOperator) || (binOp instanceof AGteqBinaryOperator)) {
00338
00339 currentType = BooleanType.TYPE;
00340 if (getNumericType(leftType, rightType) == null) {
00341 exceptions.add(new TypeException("Type mismatch for binary operator " + binOp.toString().trim()));
00342 }
00343 } else if ((binOp instanceof AEqBinaryOperator) || (binOp instanceof ANeqBinaryOperator)) {
00344
00345 currentType = BooleanType.TYPE;
00346 if ((leftType == BooleanType.TYPE) && (rightType == BooleanType.TYPE)) {
00347 } else if ((leftType instanceof ReferenceType) && (rightType instanceof ReferenceType)) {
00348 } else if (getNumericType(leftType, rightType) == null) {
00349 exceptions.add(new TypeException("Type mismatch for binary operator " + binOp.toString().trim()));
00350 }
00351 }
00352 }
00353
00354
00355
00356
00357 public void caseABooleanPrimitiveType(ABooleanPrimitiveType node) {
00358 currentType = BooleanType.TYPE;
00359 }
00360
00361
00362
00363
00364 public void caseABytePrimitiveType(ABytePrimitiveType node) {
00365 currentType = ByteType.TYPE;
00366 }
00367
00368
00369
00370
00371 public void caseACharacterLiteralLiteral(ACharacterLiteralLiteral node) {
00372 currentType = CharType.TYPE;
00373 }
00374
00375
00376
00377
00378 public void caseACharPrimitiveType(ACharPrimitiveType node) {
00379 currentType = CharType.TYPE;
00380 }
00381
00382
00383
00384
00385 public void caseAClassOrInterfaceTypeExp(AClassOrInterfaceTypeExp node) {
00386 for (ca.mcgill.sable.util.Iterator i = node.getDimExp().iterator(); i.hasNext();) {
00387 ((PDimExp) i.next()).apply(this);
00388 if (!(currentType instanceof IntegralType)) {
00389 exceptions.add(new TypeException("Expecting integral expression in dim exp"));
00390 }
00391 }
00392
00393 try {
00394 currentType = symbolTable.resolveType(new Name(node.getClassOrInterfaceType().toString()));
00395 int dimensions = node.getDimExp().size() + node.getDim().size();
00396 currentType = new ArrayType(currentType, dimensions);
00397 } catch (Exception e) {
00398 exceptions.add(e);
00399 currentType = VoidType.TYPE;
00400 }
00401 }
00402
00403
00404
00405
00406 public void caseADecimalIntegerLiteral(ADecimalIntegerLiteral node) {
00407 String literal = node.toString().trim();
00408 if (literal.endsWith("L") || literal.endsWith("l")) {
00409 currentType = LongType.TYPE;
00410 } else {
00411 currentType = IntType.TYPE;
00412 }
00413 }
00414
00415
00416
00417
00418 public void caseADoublePrimitiveType(ADoublePrimitiveType node) {
00419 currentType = DoubleType.TYPE;
00420 }
00421
00422
00423
00424
00425 public void caseAExpCastExp(AExpCastExp node) {
00426 currentType = VoidType.TYPE;
00427 Type destType;
00428 try {
00429 destType = symbolTable.resolveType(new Name(node.getFirst().toString()));
00430 } catch (Exception e) {
00431 exceptions.add(new TypeException("Invalid casting type " + node.getFirst()));
00432 return;
00433 }
00434 node.getSecond().apply(this);
00435 if (!currentType.isValidCastingConversion(destType)) {
00436 exceptions.add(new TypeException("Invalid casting type"));
00437 }
00438 currentType = destType;
00439 }
00440
00441
00442
00443
00444 public void caseAExpVariableInitializer(AExpVariableInitializer node) {
00445 Type destType = currentType;
00446 node.getExp().apply(this);
00447 if (!(currentType.isValidIdentityConversion(destType) || currentType.isValidWideningConversion(destType))) {
00448 exceptions.add(new TypeException("Type mismatch in array initializer"));
00449 }
00450 currentType = destType;
00451 }
00452
00453
00454
00455
00456 public void caseAFalseBooleanLiteral(AFalseBooleanLiteral node) {
00457 currentType = BooleanType.TYPE;
00458 }
00459
00460
00461
00462
00463 public void caseAFloatingPointLiteralLiteral(AFloatingPointLiteralLiteral node) {
00464 String literal = node.toString().trim();
00465 if (literal.endsWith("F") || literal.endsWith("f"))
00466 currentType = FloatType.TYPE;
00467 else
00468 currentType = DoubleType.TYPE;
00469 }
00470
00471
00472
00473
00474 public void caseAFloatPrimitiveType(AFloatPrimitiveType node) {
00475 currentType = FloatType.TYPE;
00476 }
00477
00478
00479
00480
00481 public void caseAHexIntegerLiteral(AHexIntegerLiteral node) {
00482 String literal = node.toString().substring(2).trim();
00483 if (literal.endsWith("L") || literal.endsWith("l")) {
00484 currentType = LongType.TYPE;
00485 } else {
00486 currentType = IntType.TYPE;
00487 }
00488 }
00489
00490
00491
00492
00493 public void caseAInitClassInterfaceExp(AInitClassInterfaceExp node) {
00494 try {
00495 currentType = symbolTable.resolveType(new Name(node.getClassOrInterfaceType().toString()));
00496 Type resultType = currentType = new ArrayType(currentType, node.getDim().size());
00497 node.getArrayInitializer().apply(this);
00498 currentType = resultType;
00499 } catch (Exception e) {
00500 exceptions.add(e);
00501 currentType = VoidType.TYPE;
00502 }
00503 }
00504
00505
00506
00507
00508 public void caseAInitPrimitiveExp(AInitPrimitiveExp node) {
00509 node.getPrimitiveType().apply(this);
00510 Type resultType = currentType = new ArrayType(currentType, node.getDim().size());
00511 node.getArrayInitializer().apply(this);
00512 currentType = resultType;
00513 }
00514
00515
00516
00517
00518 public void caseAInstanceofExp(AInstanceofExp node) {
00519 node.getExp().apply(this);
00520 boolean flag = false;
00521 try {
00522 Type type = symbolTable.resolveClassOrInterfaceType(new Name(node.getReferenceType().toString()));
00523 if ((type instanceof ReferenceType) && (currentType instanceof ReferenceType))
00524 flag = true;
00525 } catch (Exception e) {
00526 exceptions.add(e);
00527 }
00528 if (!flag) {
00529 exceptions.add(new TypeException("Invalid type in instanceof expression"));
00530 currentType = BooleanType.TYPE;
00531 }
00532 }
00533
00534
00535
00536
00537 public void caseAIntPrimitiveType(AIntPrimitiveType node) {
00538 currentType = IntType.TYPE;
00539 }
00540
00541
00542
00543
00544 public void caseALongPrimitiveType(ALongPrimitiveType node) {
00545 currentType = LongType.TYPE;
00546 }
00547
00548
00549
00550
00551 public void caseANameArrayAccess(ANameArrayAccess node) {
00552 new ANameExp((PName) node.getName().clone()).apply(this);
00553 if (!(currentType instanceof ArrayType)) {
00554 exceptions.add(new TypeException("Not an array type in array access"));
00555 currentType = VoidType.TYPE;
00556 return;
00557 }
00558 ArrayType arrayType = (ArrayType) currentType;
00559 node.getExp().apply(this);
00560 if (!(currentType instanceof IntegralType)) {
00561 exceptions.add(new TypeException("Expecting integral expression in array access"));
00562 }
00563 if (arrayType.nDimensions > 1) {
00564 currentType = new ArrayType(arrayType.baseType , arrayType.nDimensions - 1);
00565 } else {
00566 currentType = arrayType.baseType;
00567 }
00568 }
00569
00570
00571
00572
00573 public void caseANameCastExp(ANameCastExp node) {
00574 currentType = VoidType.TYPE;
00575 Type destType;
00576 try {
00577 destType = symbolTable.resolveType(new Name(node.getName().toString()));
00578 } catch (Exception e) {
00579 exceptions.add(new TypeException("Invalid casting type " + node.getName()));
00580 return;
00581 }
00582 int dimension = node.getDim().size();
00583 if (dimension > 0) {
00584 destType = new ArrayType(destType, dimension);
00585 }
00586 node.getExp().apply(this);
00587 if (!currentType.isValidCastingConversion(destType)) {
00588 exceptions.add(new TypeException("Invalid casting type"));
00589 }
00590 currentType = destType;
00591 }
00592
00593
00594
00595
00596 public void caseANamedTypeExp(ANamedTypeExp node) {
00597 currentType = VoidType.TYPE;
00598 exceptions.add(new TypeException("unsupported expression " + node));
00599 }
00600
00601
00602
00603
00604 public void caseANameExp(ANameExp node) {
00605 if ("$ret".equals(node.toString().trim())) {
00606 if (annotation instanceof MethodDeclarationAnnotation) {
00607 currentType = ((MethodDeclarationAnnotation) annotation).getMethod().getReturnType();
00608 } else {
00609 currentType = VoidType.TYPE;
00610 }
00611 return;
00612 }
00613 if (node.getName() instanceof ASimpleName) {
00614 Hashtable visibleLocals = getDeclaredLocals();
00615 String local = node.getName().toString().trim();
00616 Name localOrFieldName = new Name(local);
00617 if (visibleLocals.get(local) != null) {
00618 try {
00619 currentType = Util.convertType(((Local) visibleLocals.get(local)).getType(), symbolTable);
00620 } catch (Exception e) {
00621 exceptions.add(e);
00622 }
00623 } else {
00624 try {
00625 Field f = type.getField(localOrFieldName);
00626 currentType = f.getType();
00627 if (isStatic && !java.lang.reflect.Modifier.isStatic(f.getModifiers())) {
00628 TId id = ((ASimpleName) node.getName()).getId();
00629 exceptions.add(new TypeException("Cannot refer to instance field '"
00630 + id.toString().trim() + "' in a static predicate"));
00631 }
00632 } catch (Exception e) {
00633 try {
00634 currentType = symbolTable.resolveType(new Name(node.getName().toString()));
00635 } catch (Exception e2) {
00636 currentType = VoidType.TYPE;
00637 exceptions.add(new TypeException("Unresolved name expression '" + localOrFieldName.toString()
00638 + "' in " + type.getFullyQualifiedName()));
00639 }
00640 }
00641 }
00642 } else {
00643 Name name = new Name(node.getName().toString()).getSuperName();
00644 ClassOrInterfaceType type = null;
00645 PName typeName = ((AQualifiedName) node.getName()).getName();
00646 while (!name.isSimpleName()) {
00647 try {
00648 type = (ClassOrInterfaceType) symbolTable.resolveType(name);
00649 break;
00650 } catch (Exception e) {
00651 name = name.getSuperName();
00652 typeName = ((AQualifiedName) typeName).getName();
00653 }
00654 }
00655
00656 if (type == null) {
00657 try {
00658 type = (ClassOrInterfaceType) symbolTable.resolveType(name);
00659 } catch (Exception e) {
00660 try {
00661 currentType = (ClassOrInterfaceType) symbolTable.resolveType(new Name(node.getName().toString()));
00662 usedTypeNames.add(node);
00663 return;
00664 } catch (Exception e2) {
00665 PExp exp = buildFieldAccess((AQualifiedName) node.getName().clone());
00666 node.replaceBy(exp);
00667 exp.apply(this);
00668 return;
00669 }
00670 }
00671 }
00672
00673 String nameExp = new Name(node.getName().toString()).toString();
00674 Name n = new Name(nameExp.substring(type.getFullyQualifiedName().length() + 1));
00675 nameExp = n.getSubName().toString();
00676 PName newName = (PName) typeName.parent().clone();
00677 try {
00678 currentType = type.getField(new Name(n.getFirstIdentifier())).getType();
00679 } catch (Exception e) {
00680 exceptions.add(e);
00681 currentType = VoidType.TYPE;
00682 }
00683 PExp exp = buildFieldAccess(new ANameExp(newName), nameExp);
00684 node.replaceBy(exp);
00685 }
00686 }
00687
00688
00689
00690
00691 public void caseANameMethodInvocationExp(ANameMethodInvocationExp node) {
00692 Vector types = new Vector();
00693 {
00694 Object temp[] = node.getArgumentList().toArray();
00695 for (int i = 0; i < temp.length; i++) {
00696 ((PExp) temp[i]).apply(this);
00697 types.add(currentType);
00698 }
00699 }
00700
00701 Name methodName;
00702 if (node.getName() instanceof AQualifiedName) {
00703 new ANameExp((PName) ((AQualifiedName) node.getName()).getName().clone()).apply(this);
00704 methodName = new Name(((AQualifiedName) node.getName()).getId().toString());
00705 } else {
00706 currentType = type;
00707 methodName = new Name(((ASimpleName) node.getName()).getId().toString());
00708 }
00709
00710 try {
00711 Method m = symbolTable.resolveMethod(currentType.getName(), methodName, types);
00712 currentType = m.getReturnType();
00713 } catch (Exception e) {
00714 exceptions.add(e);
00715 currentType = VoidType.TYPE;
00716 }
00717 }
00718
00719
00720
00721
00722 public void caseANullLiteral(ANullLiteral node) {
00723 currentType = NullType.TYPE;
00724 }
00725
00726
00727
00728
00729 public void caseAOctalIntegerLiteral(AOctalIntegerLiteral node) {
00730 String literal = node.toString().substring(1).trim();
00731 if (literal.endsWith("L") || literal.endsWith("l")) {
00732 currentType = LongType.TYPE;
00733 } else {
00734 currentType = IntType.TYPE;
00735 }
00736 }
00737
00738
00739
00740
00741 public void caseAPostDecrementExp(APostDecrementExp node) {
00742 node.getExp().apply(this);
00743 if (!(currentType instanceof IntegralType)) {
00744 currentType = IntType.TYPE;
00745 exceptions.add(new TypeException("Expecting an integral expression for unary operator --"));
00746 }
00747 }
00748
00749
00750
00751
00752 public void caseAPostIncrementExp(APostIncrementExp node) {
00753 node.getExp().apply(this);
00754 if (!(currentType instanceof IntegralType)) {
00755 currentType = IntType.TYPE;
00756 exceptions.add(new TypeException("Expecting an integral expression for unary operator ++"));
00757 }
00758 }
00759
00760
00761
00762
00763 public void caseAPrimaryFieldAccess(APrimaryFieldAccess node) {
00764 node.getExp().apply(this);
00765 if ((currentType instanceof ArrayType) && ("length".equals(node.getId().toString().trim()))) {
00766 currentType = IntType.TYPE;
00767 } else if (currentType instanceof ClassOrInterfaceType) {
00768 try {
00769 currentType = ((ClassOrInterfaceType) currentType).getField(new Name(node.getId().toString())).getType();
00770 } catch (Exception e) {
00771 exceptions.add(new TypeException("unresolved field name " + node.getId()));
00772 currentType = VoidType.TYPE;
00773 }
00774 } else {
00775 exceptions.add(new TypeException("Invalid type in field access"));
00776 currentType = VoidType.TYPE;
00777 }
00778 }
00779
00780
00781
00782
00783 public void caseAPrimaryMethodInvocationExp(APrimaryMethodInvocationExp node) {
00784 Vector types = new Vector();
00785 {
00786 Object temp[] = node.getArgumentList().toArray();
00787 for (int i = 0; i < temp.length; i++) {
00788 ((PExp) temp[i]).apply(this);
00789 types.add(currentType);
00790 }
00791 }
00792
00793 Name methodName = methodName = new Name(node.getId().toString());
00794 node.getExp().apply(this);
00795 try {
00796 Method m = symbolTable.resolveMethod(currentType.getName(), methodName, types);
00797 currentType = m.getReturnType();
00798 } catch (Exception e) {
00799 exceptions.add(e);
00800 currentType = VoidType.TYPE;
00801 }
00802 }
00803
00804
00805
00806
00807 public void caseAPrimaryNoNewArrayArrayAccess(APrimaryNoNewArrayArrayAccess node) {
00808 node.getFirst().apply(this);
00809 if (!(currentType instanceof ArrayType)) {
00810 exceptions.add(new TypeException("Not an array type in array access"));
00811 currentType = VoidType.TYPE;
00812 return;
00813 }
00814 ArrayType arrayType = (ArrayType) currentType;
00815 node.getSecond().apply(this);
00816 if (!(currentType instanceof IntegralType)) {
00817 exceptions.add(new TypeException("Expecting integral expression in array access"));
00818 }
00819 if (arrayType.nDimensions > 1) {
00820 currentType = new ArrayType(arrayType.baseType , arrayType.nDimensions - 1);
00821 } else {
00822 currentType = arrayType.baseType;
00823 }
00824 }
00825
00826
00827
00828
00829 public void caseAPrimitiveTypeArrayExp(APrimitiveTypeArrayExp node) {
00830 for (ca.mcgill.sable.util.Iterator i = node.getDimExp().iterator(); i.hasNext();) {
00831 ((PDimExp) i.next()).apply(this);
00832 if (!(currentType instanceof IntegralType)) {
00833 exceptions.add(new TypeException("Expecting integral expression in dim exp"));
00834 }
00835 }
00836
00837 node.getPrimitiveType().apply(this);
00838 int dimensions = node.getDimExp().size() + node.getDim().size();
00839 currentType = new ArrayType(currentType, dimensions);
00840 }
00841
00842
00843
00844
00845 public void caseAPrimitiveTypeCastExp(APrimitiveTypeCastExp node) {
00846 node.getPrimitiveType().apply(this);
00847 Type destType = currentType;
00848 int dimension = node.getDim().size();
00849 if (dimension > 0) {
00850 destType = new ArrayType(destType, dimension);
00851 }
00852 node.getExp().apply(this);
00853
00854 if (!currentType.isValidCastingConversion(destType)) {
00855 exceptions.add(new TypeException("Invalid casting type"));
00856 }
00857 currentType = destType;
00858 }
00859
00860
00861
00862
00863 public void caseAPrimitiveTypePrimaryExp(APrimitiveTypePrimaryExp node) {
00864 currentType = VoidType.TYPE;
00865 exceptions.add(new TypeException("unsupported expression " + node));
00866 }
00867
00868
00869
00870
00871 public void caseAQualifiedClassInstanceCreationExp(AQualifiedClassInstanceCreationExp node) {
00872 currentType = VoidType.TYPE;
00873 exceptions.add(new TypeException("unsupported expression " + node));
00874 }
00875
00876
00877
00878
00879 public void caseAQualifiedThisExp(AQualifiedThisExp node) {
00880 currentType = VoidType.TYPE;
00881 exceptions.add(new TypeException("unsupported expression " + node));
00882 }
00883
00884
00885
00886
00887 public void caseAQuestionExp(AQuestionExp node) {
00888 node.getFirst().apply(this);
00889 if (currentType != BooleanType.TYPE) {
00890 exceptions.add(new TypeException("Expecting a boolean expression for ?: first expression"));
00891 }
00892 node.getSecond().apply(this);
00893 Type trueType = currentType;
00894 node.getThird().apply(this);
00895 Type falseType = currentType;
00896
00897 boolean flag = true;
00898 if (trueType == falseType) {
00899 currentType = trueType;
00900 } else if (trueType instanceof NumericType) {
00901 if (((trueType == ByteType.TYPE) && (falseType == ShortType.TYPE))
00902 || ((trueType == ShortType.TYPE) && (falseType == ByteType.TYPE))) {
00903 currentType = ShortType.TYPE;
00904 } else if (((trueType == ByteType.TYPE) || (trueType == ShortType.TYPE)
00905 || (trueType == CharType.TYPE)) && (falseType == IntType.TYPE)
00906 && (node.getThird() instanceof ALiteralExp)) {
00907 currentType = trueType;
00908 } else if (((falseType == ByteType.TYPE) || (falseType == ShortType.TYPE)
00909 || (falseType == CharType.TYPE)) && (trueType == IntType.TYPE)
00910 && (node.getSecond() instanceof ALiteralExp)) {
00911 currentType = falseType;
00912 } else {
00913 currentType = getNumericType(trueType, falseType);
00914 }
00915 } else if ((trueType == NullType.TYPE) && (falseType instanceof ReferenceType)) {
00916 currentType = trueType;
00917 } else if ((trueType instanceof ReferenceType) && (falseType == NullType.TYPE)) {
00918 currentType = falseType;
00919 } else if ((trueType instanceof ReferenceType) && (falseType instanceof ReferenceType)) {
00920 if (trueType.isValidIdentityConversion(falseType)
00921 && trueType.isValidWideningConversion(falseType)) {
00922 currentType = falseType;
00923 } else if (falseType.isValidIdentityConversion(trueType)
00924 && falseType.isValidWideningConversion(trueType)) {
00925 currentType = trueType;
00926 } else flag = false;
00927 } else {
00928 flag = false;
00929 }
00930
00931 if (!flag) {
00932 currentType = VoidType.TYPE;
00933 exceptions.add(new TypeException("Type mismatch in question expression"));
00934 }
00935 }
00936
00937
00938
00939
00940 public void caseAShortPrimitiveType(AShortPrimitiveType node) {
00941 currentType = ShortType.TYPE;
00942 }
00943
00944
00945
00946
00947 public void caseASimpleClassInstanceCreationExp(ASimpleClassInstanceCreationExp node) {
00948 currentType = VoidType.TYPE;
00949 exceptions.add(new TypeException("unsupported expression " + node));
00950 }
00951
00952
00953
00954
00955 public void caseAStringLiteralLiteral(AStringLiteralLiteral node) {
00956 try {
00957 currentType = symbolTable.resolveType(new Name("java.lang.String"));
00958 } catch (Exception e) {
00959 exceptions.add(e);
00960 currentType = VoidType.TYPE;
00961 }
00962 }
00963
00964
00965
00966
00967 public void caseASuperFieldAccess(ASuperFieldAccess node) {
00968 try {
00969 currentType = type.getDirectSuperClass().getField(new Name(node.getId().toString())).getType();
00970 } catch (Exception e) {
00971 exceptions.add(new TypeException("Invalid field in super field access"));
00972 currentType = VoidType.TYPE;
00973 }
00974 }
00975
00976
00977
00978
00979 public void caseASuperMethodInvocationExp(ASuperMethodInvocationExp node) {
00980 Vector types = new Vector();
00981 {
00982 Object temp[] = node.getArgumentList().toArray();
00983 for (int i = 0; i < temp.length; i++) {
00984 ((PExp) temp[i]).apply(this);
00985 types.add(currentType);
00986 }
00987 }
00988
00989 Name methodName = methodName = new Name(node.getId().toString());
00990 currentType = type.getDirectSuperClass();
00991 try {
00992 Method m = symbolTable.resolveMethod(currentType.getName(), methodName, types);
00993 currentType = m.getReturnType();
00994 } catch (Exception e) {
00995 exceptions.add(e);
00996 currentType = VoidType.TYPE;
00997 }
00998 }
00999
01000
01001
01002
01003 public void caseAThisExp(AThisExp node) {
01004 currentType = type;
01005 }
01006
01007
01008
01009
01010 public void caseATrueBooleanLiteral(ATrueBooleanLiteral node) {
01011 currentType = BooleanType.TYPE;
01012 }
01013
01014
01015
01016
01017 public void caseAUnaryExp(AUnaryExp node) {
01018 PUnaryOperator op = node.getUnaryOperator();
01019 node.getExp().apply(this);
01020 if (op instanceof AIncrementUnaryOperator) {
01021 if (!(currentType instanceof IntegralType)) {
01022 currentType = IntType.TYPE;
01023 exceptions.add(new TypeException("Expecting an integral expression for unary operator ++"));
01024 }
01025 } else if (op instanceof ADecrementUnaryOperator) {
01026 if (!(currentType instanceof IntegralType)) {
01027 currentType = IntType.TYPE;
01028 exceptions.add(new TypeException("Expecting an integral expression for unary operator --"));
01029 }
01030 } else if (op instanceof APlusUnaryOperator) {
01031 if (!(currentType instanceof NumericType)) {
01032 currentType = IntType.TYPE;
01033 exceptions.add(new TypeException("Expecting a numeric expression for unary operator +"));
01034 }
01035 } else if (op instanceof AMinusUnaryOperator) {
01036 if (!(currentType instanceof NumericType)) {
01037 currentType = IntType.TYPE;
01038 exceptions.add(new TypeException("Expecting a numeric expression for unary operator -"));
01039 }
01040 } else if (op instanceof ABitComplementUnaryOperator) {
01041 if (!(currentType instanceof IntegralType)) {
01042 currentType = IntType.TYPE;
01043 exceptions.add(new TypeException("Expecting an integral expression for unary operator ~"));
01044 }
01045 if (!(currentType instanceof LongType)) {
01046 currentType = IntType.TYPE;
01047 }
01048 } else if (op instanceof AComplementUnaryOperator) {
01049 if (currentType != BooleanType.TYPE) {
01050 currentType = BooleanType.TYPE;
01051 exceptions.add(new TypeException("Expecting a boolean expression for unary operator !"));
01052 }
01053 }
01054 }
01055
01056
01057
01058
01059 public void caseAVoidExp(AVoidExp node) {
01060 currentType = VoidType.TYPE;
01061 exceptions.add(new TypeException("unsupported expression " + node));
01062 }
01063
01064
01065
01066
01067
01068 public Vector check(Node node) {
01069 node.apply(this);
01070
01071 if (currentType != BooleanType.TYPE) {
01072 exceptions.add(new TypeException("Assertion expression should be boolean type"));
01073 }
01074
01075 return exceptions;
01076 }
01077
01078
01079
01080
01081 private Hashtable getDeclaredLocals() {
01082 if (currentAnnotation != null) {
01083 Hashtable visibleLocals;
01084 if (annotation instanceof MethodDeclarationAnnotation) {
01085 visibleLocals = ((MethodDeclarationAnnotation) annotation).getParameterLocals();
01086 } else {
01087 visibleLocals = ((ConstructorDeclarationAnnotation) annotation).getParameterLocals();
01088 }
01089 for (Enumeration e = currentAnnotation.getDeclaredLocalVariables().elements();
01090 e.hasMoreElements();) {
01091 Local l = (Local) e.nextElement();
01092 visibleLocals.put(l.getName().trim(), l);
01093 }
01094 return visibleLocals;
01095 } else {
01096 if (annotation instanceof MethodDeclarationAnnotation) {
01097 return ((MethodDeclarationAnnotation) annotation).getParameterLocals();
01098 } else {
01099 return ((ConstructorDeclarationAnnotation) annotation).getParameterLocals();
01100 }
01101 }
01102 }
01103
01104
01105
01106
01107 public Vector getExceptions() {
01108 return exceptions;
01109 }
01110
01111
01112
01113
01114
01115
01116 private Type getIntegralType(Type leftType, Type rightType) {
01117 if (!(leftType instanceof IntegralType) || !(rightType instanceof IntegralType))
01118 return null;
01119 if ((leftType == LongType.TYPE) || (rightType == LongType.TYPE))
01120 return LongType.TYPE;
01121 else if ((leftType instanceof IntegralType) || (rightType instanceof IntegralType))
01122 return IntType.TYPE;
01123 else return null;
01124 }
01125
01126
01127
01128
01129
01130
01131 private Type getNumericType(Type leftType, Type rightType) {
01132 if (!(leftType instanceof NumericType) || !(rightType instanceof NumericType))
01133 return null;
01134 if ((leftType == LongType.TYPE) || (rightType == LongType.TYPE))
01135 return LongType.TYPE;
01136 else if ((leftType == FloatType.TYPE) || (rightType == FloatType.TYPE))
01137 return FloatType.TYPE;
01138 else if ((leftType == DoubleType.TYPE) || (rightType == DoubleType.TYPE))
01139 return DoubleType.TYPE;
01140 else if ((leftType instanceof IntegralType) || (rightType instanceof IntegralType))
01141 return IntType.TYPE;
01142 else return null;
01143 }
01144 }