00001 package edu.ksu.cis.bandera.specification.predicate.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.Local;
00036 import ca.mcgill.sable.soot.Modifier;
00037 import java.util.*;
00038 import ca.mcgill.sable.soot.SootClass;
00039 import edu.ksu.cis.bandera.specification.predicate.analysis.*;
00040 import edu.ksu.cis.bandera.specification.predicate.node.*;
00041 import edu.ksu.cis.bandera.specification.predicate.exception.*;
00042 import edu.ksu.cis.bandera.specification.predicate.datastructure.*;
00043 import edu.ksu.cis.bandera.jjjc.symboltable.*;
00044 import edu.ksu.cis.bandera.annotation.*;
00045 import edu.ksu.cis.bandera.jjjc.symboltable.Package;
00046 import edu.ksu.cis.bandera.jjjc.util.Util;
00047 public class TypeChecker extends DepthFirstAdapter {
00048 private Vector exceptions = new Vector();
00049 private Node node;
00050 private SymbolTable symbolTable;
00051 private ClassOrInterfaceType type;
00052 private Annotation annotation;
00053 private int mode;
00054 private Vector labeledStmtAnnotations;
00055 private LabeledStmtAnnotation currentAnnotation;
00056 private Type currentType;
00057 private String predName;
00058 private AnnotationManager am;
00059 private final static int EXP = 1;
00060 private final static int RETURN = 2;
00061 private final static int INVOKE = 4;
00062 private final static int LOCATION = 8;
00063 private boolean isStatic;
00064 private boolean usePrivate;
00065 private boolean ret;
00066 private StringBuffer buffer;
00067 private Vector usedTypeNames = new Vector();
00068 private Hashtable variablesUsed;
00069 private Vector params;
00070 private Vector paramTypes;
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
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148 public TypeChecker(Node node, SymbolTable symbolTable, ClassOrInterfaceType type, Annotation annotation) {
00149 this.node = node;
00150 this.symbolTable = symbolTable;
00151 this.annotation = annotation;
00152 this.type = type;
00153 if (annotation != null) {
00154 Vector v = annotation.getAllAnnotations(false);
00155 labeledStmtAnnotations = new Vector();
00156 for (Enumeration e = v.elements(); e.hasMoreElements();) {
00157 Object o = e.nextElement();
00158 if (o instanceof LabeledStmtAnnotation) labeledStmtAnnotations.add(o);
00159 }
00160 }
00161 }
00162
00163
00164
00165
00166
00167 private PExp buildNavigation(AQualifiedName name) {
00168 PExp exp;
00169 if (name.getName() instanceof AQualifiedName) {
00170 exp = buildNavigation((AQualifiedName) name.getName());
00171 } else {
00172 exp = buildNavigation((ASimpleName) name.getName());
00173 }
00174
00175 return new ANavigationExp(exp, new AStrongObjectNavigation(new TDot(), name.getId()));
00176 }
00177
00178
00179
00180
00181
00182 private PExp buildNavigation(ASimpleName name) {
00183 return new ANameExp(name);
00184 }
00185
00186
00187
00188
00189
00190
00191 private PExp buildNavigation(PExp typeExp, String name) {
00192 for (StringTokenizer tokenizer = new StringTokenizer(name); tokenizer.hasMoreTokens();) {
00193 String token = (String) tokenizer.nextToken();
00194 typeExp = new ANavigationExp(typeExp, new AStrongObjectNavigation(new TDot(), new TId(token)));
00195 }
00196 return typeExp;
00197 }
00198
00199
00200
00201
00202 public void caseABinaryExp(ABinaryExp node) {
00203 node.getLeft().apply(this);
00204 Type leftType = currentType;
00205 node.getRight().apply(this);
00206 Type rightType = currentType;
00207
00208 PBinOp binOp = node.getBinOp();
00209 if ((binOp instanceof AAndBinOp) || (binOp instanceof AOrBinOp)) {
00210
00211 currentType = BooleanType.TYPE;
00212 if ((leftType != BooleanType.TYPE) || (rightType != BooleanType.TYPE)) {
00213 exceptions.add(new TypeException("Expecting boolean expression"));
00214 }
00215 } else if ((binOp instanceof ABitAndBinOp) || (binOp instanceof ABitOrBinOp)
00216 || (binOp instanceof ABitXorBinOp)) {
00217
00218 currentType = IntType.TYPE;
00219 if ((leftType == BooleanType.TYPE) && (rightType == BooleanType.TYPE)) {
00220 currentType = BooleanType.TYPE;
00221 } else if (getIntegralType(leftType, rightType) != null) {
00222 currentType = getIntegralType(leftType, rightType);
00223 } else {
00224 exceptions.add(new TypeException("Type mismatch for binary operator " + binOp.toString().trim()));
00225 }
00226 } else if ((binOp instanceof APlusBinOp) || (binOp instanceof AMinusBinOp)
00227 || (binOp instanceof ATimesBinOp) || (binOp instanceof AStrongDivBinOp)
00228 || (binOp instanceof AStrongModBinOp)) {
00229
00230
00231 currentType = IntType.TYPE;
00232 if (getNumericType(leftType, rightType) != null) {
00233 currentType = getNumericType(leftType, rightType);
00234 } else {
00235 exceptions.add(new TypeException("Type mismatch for binary operator " + binOp.toString().trim()));
00236 }
00237 } else if ((binOp instanceof AShiftLeftBinOp) || (binOp instanceof ASignedShiftRightBinOp)
00238 || (binOp instanceof AUnsignedShiftRightBinOp)) {
00239
00240 currentType = IntType.TYPE;
00241 if (getIntegralType(leftType, rightType) != null) {
00242 currentType = getIntegralType(leftType, rightType);
00243 } else {
00244 exceptions.add(new TypeException("Type mismatch for binary operator " + binOp.toString().trim()));
00245 }
00246 } else if ((binOp instanceof ALessBinOp) || (binOp instanceof ALessEqualBinOp)
00247 || (binOp instanceof AGreaterBinOp) || (binOp instanceof AGreaterEqualBinOp)) {
00248
00249 currentType = BooleanType.TYPE;
00250 if (getNumericType(leftType, rightType) == null) {
00251 exceptions.add(new TypeException("Type mismatch for binary operator " + binOp.toString().trim()));
00252 }
00253 } else if ((binOp instanceof AEqualBinOp) || (binOp instanceof ANotEqualBinOp)) {
00254
00255 currentType = BooleanType.TYPE;
00256 if ((leftType == BooleanType.TYPE) && (rightType == BooleanType.TYPE)) {
00257 } else if ((leftType instanceof ReferenceType) && (rightType instanceof ReferenceType)) {
00258 } else if (getNumericType(leftType, rightType) == null) {
00259 exceptions.add(new TypeException("Type mismatch for binary operator " + binOp.toString().trim()));
00260 }
00261 }
00262 }
00263
00264
00265
00266
00267 public void caseABitComplementExp(ABitComplementExp node) {
00268 node.getExp().apply(this);
00269 if (!(currentType instanceof IntegralType)) {
00270 currentType = IntType.TYPE;
00271 exceptions.add(new TypeException("Expecting boolean expression for unary operator ~"));
00272 }
00273 if (!(currentType instanceof LongType)) {
00274 currentType = IntType.TYPE;
00275 }
00276 }
00277
00278
00279
00280
00281 public void caseACharLiteral(ACharLiteral node) {
00282 currentType = CharType.TYPE;
00283 }
00284
00285
00286
00287
00288 public void caseAComplementExp(AComplementExp node) {
00289 node.getExp().apply(this);
00290 if (currentType != BooleanType.TYPE) {
00291 currentType = BooleanType.TYPE;
00292 exceptions.add(new TypeException("Expecting boolean expression for unary operator !"));
00293 }
00294 }
00295
00296
00297
00298
00299 public void caseADecIntLiteral(ADecIntLiteral node) {
00300 currentType = IntType.TYPE;
00301 }
00302
00303
00304
00305
00306 public void caseADecLongLiteral(ADecLongLiteral node) {
00307 currentType = LongType.TYPE;
00308 }
00309
00310
00311
00312
00313 public void caseADoubleLiteral(ADoubleLiteral node) {
00314 currentType = DoubleType.TYPE;
00315 }
00316
00317
00318
00319
00320 public void caseAEndOfLineComment(AEndOfLineComment node) {
00321 String s = node.toString().trim();
00322 s = s.substring(2, s.length());
00323 buffer.append(s.trim() + " ");
00324 }
00325
00326
00327
00328
00329 public void caseAExpressionPropositionDefinition(AExpressionPropositionDefinition node) {
00330 usePrivate = false;
00331 variablesUsed = new Hashtable();
00332 buffer = new StringBuffer();
00333 if (node.getComment() != null) {
00334 for (Iterator i = node.getComment().iterator(); i.hasNext();) {
00335 ((PComment) i.next()).apply(this);
00336 }
00337 }
00338 isStatic = !(node.getParams() instanceof AInstanceParams);
00339 params = new Vector();
00340 paramTypes = new Vector();
00341
00342 if (node.getParams() != null) {
00343 node.getParams().apply(this);
00344 }
00345 if (annotation != null) {
00346 exceptions.add(new BadPredicateDefinitionException("Expression predicate cannot be in method/constructor level"));
00347 } else {
00348 mode = EXP;
00349 node.getColonExp().apply(this);
00350 if (currentType != BooleanType.TYPE) {
00351 exceptions.add(new BadPredicateDefinitionException("Expression predicate should be type boolean"));
00352 }
00353 }
00354 String name = predName + "." + node.getId().toString().trim();
00355
00356 try {
00357 Predicate p = PredicateFactory.createExpressionPredicate(new Name(name), type, node, params, paramTypes, isStatic, variablesUsed, node.getColonExp() != null ? ((AColonExp) node.getColonExp()).getExp() : null, buffer.toString(), exceptions);
00358 p.setUsePrivate(usePrivate);
00359 } catch (Exception e) {
00360 exceptions.add(e);
00361 }
00362 exceptions = new Vector();
00363 usedTypeNames = new Vector();
00364 }
00365
00366
00367
00368
00369 public void caseAFalseLiteral(AFalseLiteral node) {
00370 currentType = BooleanType.TYPE;
00371 }
00372
00373
00374
00375
00376 public void caseAFloatLiteral(AFloatLiteral node) {
00377 currentType = FloatType.TYPE;
00378 }
00379
00380
00381
00382
00383 public void caseAHexIntLiteral(AHexIntLiteral node) {
00384 currentType = IntType.TYPE;
00385 }
00386
00387
00388
00389
00390 public void caseAHexLongLiteral(AHexLongLiteral node) {
00391 currentType = LongType.TYPE;
00392 }
00393
00394
00395
00396
00397 public void caseAInstanceofExp(AInstanceofExp node) {
00398 currentType = BooleanType.TYPE;
00399 node.getExp().apply(this);
00400 boolean flag = false;
00401 try {
00402 Type type = symbolTable.resolveClassOrInterfaceType(new Name(node.getType().toString()));
00403 if ((type instanceof ReferenceType) && (currentType instanceof ReferenceType))
00404 flag = true;
00405 } catch (Exception e) {
00406 exceptions.add(e);
00407 }
00408 if (!flag) {
00409 exceptions.add(new TypeException("Invalid type in instanceof expression"));
00410 }
00411 }
00412
00413
00414
00415
00416 public void caseAInvokePropositionDefinition(AInvokePropositionDefinition node) {
00417 usePrivate = false;
00418 variablesUsed = new Hashtable();
00419 buffer = new StringBuffer();
00420 if (node.getComment() != null) {
00421 for (Iterator i = node.getComment().iterator(); i.hasNext();) {
00422 ((PComment) i.next()).apply(this);
00423 }
00424 }
00425 String name = predName + "." + node.getId().toString().trim();
00426 params = new Vector();
00427 paramTypes = new Vector();
00428
00429 if (node.getParams() != null) {
00430 node.getParams().apply(this);
00431 }
00432 if (annotation == null) {
00433 exceptions.add(new BadPredicateDefinitionException("Invoke predicate cannot be in class level"));
00434 } else {
00435 mode = INVOKE;
00436
00437 if (annotation instanceof MethodDeclarationAnnotation) {
00438 int modifiers = ((MethodDeclarationAnnotation) annotation).getSootMethod().getModifiers();
00439 if (Modifier.isStatic(modifiers)) {
00440 isStatic = true;
00441 if (node.getParams() instanceof AInstanceParams) {
00442 exceptions.add(new BadPredicateDefinitionException("Cannot define instance invoke predicate in a static method"));
00443 }
00444 } else {
00445 isStatic = false;
00446 if (!(node.getParams() instanceof AInstanceParams)) {
00447 exceptions.add(new BadPredicateDefinitionException("Cannot define static invoke predicate in an instance method"));
00448 }
00449 }
00450 if (Modifier.isNative(modifiers)) {
00451 exceptions.add(new BadPredicateDefinitionException("Invoke predicate cannot be in native method"));
00452 try {
00453 Predicate p = PredicateFactory.createInvokePredicate(new Name(name), type, annotation, node, params, paramTypes, isStatic, variablesUsed, node.getColonExp() != null ? ((AColonExp) node.getColonExp()).getExp() : null, buffer.toString(), exceptions);
00454 p.setUsePrivate(usePrivate);
00455 } catch (Exception e) {
00456 exceptions.add(e);
00457 }
00458 exceptions = new Vector();
00459 usedTypeNames = new Vector();
00460 return;
00461 }
00462 }
00463 if (node.getColonExp() != null) {
00464 node.getColonExp().apply(this);
00465 if (currentType != BooleanType.TYPE) {
00466 exceptions.add(new BadPredicateDefinitionException("Invoke predicate constraint should be type boolean"));
00467 }
00468 }
00469 }
00470 try {
00471 Predicate p = PredicateFactory.createInvokePredicate(new Name(name), type, annotation, node, params, paramTypes, isStatic, variablesUsed, node.getColonExp() != null ? ((AColonExp) node.getColonExp()).getExp() : null, buffer.toString(), exceptions);
00472 p.setUsePrivate(usePrivate);
00473 } catch (Exception e) {
00474 exceptions.add(e);
00475 }
00476 exceptions = new Vector();
00477 usedTypeNames = new Vector();
00478 }
00479
00480
00481
00482
00483 public void caseALiteralExp(ALiteralExp node) {
00484 super.caseALiteralExp(node);
00485 }
00486
00487
00488
00489
00490 public void caseALocationPropositionDefinition(ALocationPropositionDefinition node) {
00491 usePrivate = false;
00492 variablesUsed = new Hashtable();
00493 buffer = new StringBuffer();
00494 if (node.getComment() != null) {
00495 for (Iterator i = node.getComment().iterator(); i.hasNext();) {
00496 ((PComment) i.next()).apply(this);
00497 }
00498 }
00499 String name = predName + "." + node.getId().toString().trim();
00500 params = new Vector();
00501 paramTypes = new Vector();
00502
00503 if (node.getParams() != null) {
00504 node.getParams().apply(this);
00505 }
00506 if (annotation == null) {
00507 exceptions.add(new BadPredicateDefinitionException("Location predicate cannot be in class level"));
00508 } else {
00509 mode = LOCATION;
00510 if (annotation instanceof MethodDeclarationAnnotation) {
00511 int modifiers = ((MethodDeclarationAnnotation) annotation).getSootMethod().getModifiers();
00512 if (Modifier.isStatic(modifiers)) {
00513 isStatic = true;
00514 if (node.getParams() instanceof AInstanceParams) {
00515 exceptions.add(new BadPredicateDefinitionException("Cannot define instance invoke predicate in a static method"));
00516 }
00517 } else {
00518 isStatic = false;
00519 if (!(node.getParams() instanceof AInstanceParams)) {
00520 exceptions.add(new BadPredicateDefinitionException("Cannot define static invoke predicate in an instance method"));
00521 }
00522 }
00523 if (Modifier.isNative(modifiers) || Modifier.isAbstract(modifiers)) {
00524 exceptions.add(new BadPredicateDefinitionException("Location predicate cannot be in abstract/native method"));
00525 try {
00526 Predicate p = PredicateFactory.createLocationPredicate(new Name(name), type, annotation, node, node.getLabel().toString().trim(), params, paramTypes, isStatic, variablesUsed, node.getColonExp() != null ? ((AColonExp) node.getColonExp()).getExp() : null, buffer.toString(), exceptions);
00527 p.setUsePrivate(usePrivate);
00528 } catch (Exception e) {
00529 exceptions.add(e);
00530 }
00531 exceptions = new Vector();
00532 usedTypeNames = new Vector();
00533 return;
00534 }
00535 }
00536 String label = node.getLabel().toString().trim();
00537 boolean found = false;
00538 for (Enumeration e = labeledStmtAnnotations.elements(); e.hasMoreElements();) {
00539 LabeledStmtAnnotation lsa = (LabeledStmtAnnotation) e.nextElement();
00540 if (lsa.getId().equals(label)) {
00541 currentAnnotation = lsa;
00542 found = true;
00543 break;
00544 }
00545 }
00546 if (!found) {
00547 exceptions.add(new BadPredicateDefinitionException("Invalid label '" + label + "'"));
00548 try {
00549 Predicate p = PredicateFactory.createLocationPredicate(new Name(name), type, annotation, node, node.getLabel().toString().trim(), params, paramTypes, isStatic, variablesUsed, node.getColonExp() != null ? ((AColonExp) node.getColonExp()).getExp() : null, buffer.toString(), exceptions);
00550 p.setUsePrivate(usePrivate);
00551 } catch (Exception e) {
00552 exceptions.add(e);
00553 }
00554 exceptions = new Vector();
00555 usedTypeNames = new Vector();
00556 return;
00557 }
00558 if (node.getColonExp() != null) {
00559 node.getColonExp().apply(this);
00560 if (currentType != BooleanType.TYPE) {
00561 exceptions.add(new BadPredicateDefinitionException("Location predicate constraint should be of type boolean"));
00562 }
00563 }
00564 }
00565 try {
00566 Predicate p = PredicateFactory.createLocationPredicate(new Name(name), type, annotation, node, node.getLabel().toString().trim(), params, paramTypes, isStatic, variablesUsed, node.getColonExp() != null ? ((AColonExp) node.getColonExp()).getExp() : null, buffer.toString(), exceptions);
00567 p.setUsePrivate(usePrivate);
00568 } catch (Exception e) {
00569 exceptions.add(e);
00570 }
00571 exceptions = new Vector();
00572 usedTypeNames = new Vector();
00573 }
00574
00575
00576
00577
00578 public void caseANameExp(ANameExp node) {
00579 if (node.getName() instanceof ASimpleName) {
00580 Hashtable visibleLocals = getDeclaredLocals();
00581 String local = node.getName().toString().trim();
00582 if (params.contains(local)) {
00583 currentType = (Type) paramTypes.elementAt(params.indexOf(local));
00584 variablesUsed.put(node, local);
00585 } else {
00586 Name localOrFieldName = new Name(local);
00587 Local lcl = (Local) visibleLocals.get(local);
00588 if (lcl != null) {
00589 try {
00590 currentType = Util.convertType(lcl.getType(), symbolTable);
00591 variablesUsed.put(node, lcl);
00592 } catch (Exception e) {
00593 exceptions.add(e);
00594 }
00595 } else {
00596 try {
00597 Field f = type.getField(localOrFieldName);
00598 currentType = f.getType();
00599 if (isStatic && !java.lang.reflect.Modifier.isStatic(f.getModifiers())) {
00600 TId id = ((ASimpleName) node.getName()).getId();
00601 exceptions.add(new BadPredicateDefinitionException("Cannot refer to instance field '" + id.toString().trim() + "' in a static predicate"));
00602 } else {
00603 if (java.lang.reflect.Modifier.isPrivate(f.getModifiers())) {
00604 usePrivate = true;
00605 }
00606 variablesUsed.put(node, f);
00607 }
00608 } catch (Exception e) {
00609 try {
00610 currentType = symbolTable.resolveType(new Name(node.getName().toString()));
00611 } catch (Exception e2) {
00612 currentType = VoidType.TYPE;
00613 exceptions.add(new TypeException("Unresolved name expression '" + localOrFieldName.toString() + "' in " + type.getFullyQualifiedName()));
00614 }
00615 }
00616 }
00617 }
00618 } else {
00619 Name name = new Name(node.getName().toString()).getSuperName();
00620 ClassOrInterfaceType type = null;
00621 PName typeName = ((AQualifiedName) node.getName()).getName();
00622 while (!name.isSimpleName()) {
00623 try {
00624 type = (ClassOrInterfaceType) symbolTable.resolveType(name);
00625 break;
00626 } catch (Exception e) {
00627 name = name.getSuperName();
00628 typeName = ((AQualifiedName) typeName).getName();
00629 }
00630 }
00631 if (type == null) {
00632 try {
00633 type = (ClassOrInterfaceType) symbolTable.resolveType(name);
00634 } catch (Exception e) {
00635 try {
00636 currentType = (ClassOrInterfaceType) symbolTable.resolveType(new Name(node.getName().toString()));
00637 usedTypeNames.add(node);
00638 return;
00639 } catch (Exception e2) {
00640 PExp exp = buildNavigation((AQualifiedName) node.getName());
00641 node.replaceBy(exp);
00642 exp.apply(this);
00643 return;
00644 }
00645 }
00646 }
00647 String nameExp = new Name(node.getName().toString()).toString();
00648 nameExp = nameExp.substring(type.getFullyQualifiedName().length() + 1);
00649 PExp exp = buildNavigation(new ANameExp(typeName), nameExp);
00650 node.replaceBy(exp);
00651 exp.apply(this);
00652 }
00653 }
00654
00655
00656
00657
00658 public void caseANegativeExp(ANegativeExp node) {
00659 node.getExp().apply(this);
00660 if (!(currentType instanceof NumericType)) {
00661 currentType = IntType.TYPE;
00662 exceptions.add(new TypeException("Expecting numeric expression for unary operator -"));
00663 }
00664 }
00665
00666
00667
00668
00669 public void caseANullLiteral(ANullLiteral node) {
00670 currentType = NullType.TYPE;
00671 }
00672
00673
00674
00675
00676 public void caseAOctIntLiteral(AOctIntLiteral node) {
00677 currentType = IntType.TYPE;
00678 }
00679
00680
00681
00682
00683 public void caseAOctLongLiteral(AOctLongLiteral node) {
00684 currentType = LongType.TYPE;
00685 }
00686
00687
00688
00689
00690 public void caseAParamParamList(AParamParamList node) {
00691 Type type;
00692 try {
00693 type = symbolTable.resolveType(new Name(node.getName().toString()));
00694 } catch (Exception e) {
00695 exceptions.add(new TypeException("Invalid parameter type"));
00696 return;
00697 }
00698 int i;
00699 if ((i = node.getDim().toArray().length) > 0) {
00700 type = new ArrayType(type, i);
00701 }
00702
00703 paramTypes.add(type);
00704 params.add(node.getId().toString().trim());
00705 }
00706
00707
00708
00709
00710 public void caseAParamsParamList(AParamsParamList node) {
00711 node.getParamList().apply(this);
00712 Type type;
00713 try {
00714 type = symbolTable.resolveType(new Name(node.getName().toString()));
00715 } catch (Exception e) {
00716 exceptions.add(new TypeException("Invalid parameter type"));
00717 return;
00718 }
00719 int i;
00720 if ((i = node.getDim().toArray().length) > 0) {
00721 type = new ArrayType(type, i);
00722 }
00723
00724 paramTypes.add(type);
00725 params.add(node.getId().toString().trim());
00726 }
00727
00728
00729
00730
00731 public void caseAParenExp(AParenExp node) {
00732 super.caseAParenExp(node);
00733 }
00734
00735
00736
00737
00738 public void caseAQuestionExp(AQuestionExp node) {
00739 node.getExp().apply(this);
00740 if (currentType != BooleanType.TYPE) {
00741 exceptions.add(new TypeException("Expecting a boolean expression for ?: expression"));
00742 }
00743 node.getTrueExp().apply(this);
00744 Type trueType = currentType;
00745 node.getFalseExp().apply(this);
00746 Type falseType = currentType;
00747
00748 boolean flag = true;
00749 if (trueType == falseType) {
00750 currentType = trueType;
00751 } else if (trueType instanceof NumericType) {
00752 if (((trueType == ByteType.TYPE) && (falseType == ShortType.TYPE))
00753 || ((trueType == ShortType.TYPE) && (falseType == ByteType.TYPE))) {
00754 currentType = ShortType.TYPE;
00755 } else if (((trueType == ByteType.TYPE) || (trueType == ShortType.TYPE)
00756 || (trueType == CharType.TYPE)) && (falseType == IntType.TYPE)
00757 && (node.getFalseExp() instanceof ALiteralExp)) {
00758 currentType = trueType;
00759 } else if (((falseType == ByteType.TYPE) || (falseType == ShortType.TYPE)
00760 || (falseType == CharType.TYPE)) && (trueType == IntType.TYPE)
00761 && (node.getTrueExp() instanceof ALiteralExp)) {
00762 currentType = falseType;
00763 } else {
00764 currentType = getNumericType(trueType, falseType);
00765 }
00766 } else if ((trueType == NullType.TYPE) && (falseType instanceof ReferenceType)) {
00767 currentType = trueType;
00768 } else if ((trueType instanceof ReferenceType) && (falseType == NullType.TYPE)) {
00769 currentType = falseType;
00770 } else if ((trueType instanceof ReferenceType) && (falseType instanceof ReferenceType)) {
00771 if (trueType.isValidIdentityConversion(falseType)
00772 && trueType.isValidWideningConversion(falseType)) {
00773 currentType = falseType;
00774 } else if (falseType.isValidIdentityConversion(trueType)
00775 && falseType.isValidWideningConversion(trueType)) {
00776 currentType = trueType;
00777 } else flag = false;
00778 } else {
00779 flag = false;
00780 }
00781
00782 if (!flag) {
00783 currentType = VoidType.TYPE;
00784 exceptions.add(new TypeException("Type mismatch in question expression"));
00785 }
00786 }
00787
00788
00789
00790
00791 public void caseAReturnPropositionDefinition(AReturnPropositionDefinition node) {
00792 usePrivate = false;
00793 variablesUsed = new Hashtable();
00794 buffer = new StringBuffer();
00795 if (node.getComment() != null) {
00796 for (Iterator i = node.getComment().iterator(); i.hasNext();) {
00797 ((PComment) i.next()).apply(this);
00798 }
00799 }
00800 String name = predName + "." + node.getId().toString().trim();
00801 params = new Vector();
00802 paramTypes = new Vector();
00803
00804 if (node.getParams() != null) {
00805 node.getParams().apply(this);
00806 }
00807 if (annotation == null) {
00808 exceptions.add(new BadPredicateDefinitionException("Return predicate cannot be in class level"));
00809 } else {
00810 mode = RETURN;
00811 ret = false;
00812
00813 if (annotation instanceof MethodDeclarationAnnotation) {
00814 int modifiers = ((MethodDeclarationAnnotation) annotation).getSootMethod().getModifiers();
00815 if (Modifier.isStatic(modifiers)) {
00816 isStatic = true;
00817 if (node.getParams() instanceof AInstanceParams) {
00818 exceptions.add(new BadPredicateDefinitionException("Cannot define instance invoke predicate in a static method"));
00819 }
00820 } else {
00821 isStatic = false;
00822 if (!(node.getParams() instanceof AInstanceParams)) {
00823 exceptions.add(new BadPredicateDefinitionException("Cannot define static invoke predicate in an instance method"));
00824 }
00825 }
00826 if (Modifier.isNative(modifiers)) {
00827 exceptions.add(new BadPredicateDefinitionException("Return predicate cannot be in abstract/native method"));
00828 try {
00829 Predicate p = PredicateFactory.createReturnPredicate(new Name(name), type, annotation, node, params, paramTypes, isStatic, ret, variablesUsed, node.getColonExp() != null ? ((AColonExp) node.getColonExp()).getExp() : null, buffer.toString(), exceptions);
00830 p.setUsePrivate(usePrivate);
00831 } catch (Exception e) {
00832 exceptions.add(e);
00833 }
00834 exceptions = new Vector();
00835 usedTypeNames = new Vector();
00836 return;
00837 }
00838 }
00839
00840 if (node.getColonExp() != null) {
00841 node.getColonExp().apply(this);
00842 if (currentType != BooleanType.TYPE) {
00843 exceptions.add(new BadPredicateDefinitionException("Return predicate constraint should be type boolean"));
00844 }
00845 }
00846 }
00847 try {
00848 Predicate p = PredicateFactory.createReturnPredicate(new Name(name), type, annotation, node, params, paramTypes, isStatic, ret, variablesUsed, node.getColonExp() != null ? ((AColonExp) node.getColonExp()).getExp() : null, buffer.toString(), exceptions);
00849 p.setUsePrivate(usePrivate);
00850 } catch (Exception e) {
00851 exceptions.add(e);
00852 }
00853 exceptions = new Vector();
00854 usedTypeNames = new Vector();
00855 }
00856
00857
00858
00859
00860 public void caseAReturnValueExp(AReturnValueExp node) {
00861 if (mode != RETURN) {
00862 exceptions.add(new BadPredicateDefinitionException("Can only have " + node.getRetVal().toString() + "in return predicate"));
00863 currentType = VoidType.TYPE;
00864 return;
00865 }
00866
00867 if (annotation instanceof ConstructorDeclarationAnnotation) {
00868 exceptions.add(new BadPredicateDefinitionException("Cannot use " + node.getRetVal().toString() + "in a constructor return predicate"));
00869 currentType = VoidType.TYPE;
00870 return;
00871 }
00872
00873 currentType = ((MethodDeclarationAnnotation) annotation).getMethod().getReturnType();
00874 ret = true;
00875 }
00876
00877
00878
00879
00880 public void caseAStringLiteral(AStringLiteral node) {
00881 try {
00882 currentType = Package.getClassOrInterfaceType(new Name("java.lang.String"));
00883 } catch (Exception e) {
00884 exceptions.add(e);
00885 }
00886 }
00887
00888
00889
00890
00891 public void caseAStrongArrayNavigation(AStrongArrayNavigation node) {
00892 Type baseType = currentType;
00893 node.getExp().apply(this);
00894 if (currentType instanceof IntegralType) {
00895 if (baseType instanceof ArrayType) {
00896 if (((ArrayType) baseType).nDimensions == 1) {
00897 currentType = ((ArrayType) baseType).baseType;
00898 } else {
00899 currentType = new ArrayType(((ArrayType) baseType).baseType, ((ArrayType) baseType).nDimensions - 1);
00900 }
00901 } else {
00902 exceptions.add(new TypeException("Not an array in array access"));
00903 currentType = VoidType.TYPE;
00904 }
00905 } else {
00906 exceptions.add(new TypeException("Not a numeric type in array access"));
00907 currentType = VoidType.TYPE;
00908 }
00909 }
00910
00911
00912
00913
00914 public void caseAStrongCastExp(AStrongCastExp node) {
00915 currentType = VoidType.TYPE;
00916 Type cast;
00917 try {
00918 cast = symbolTable.resolveType(new Name(node.getType().toString()));
00919 } catch (Exception e) {
00920 exceptions.add(new TypeException("Invalid casting type"));
00921 return;
00922 }
00923 int i;
00924 if ((i = node.getDim().toArray().length) > 0) {
00925 cast = new ArrayType(cast, i);
00926 }
00927 node.getExp().apply(this);
00928 if (!currentType.isValidCastingConversion(cast)) {
00929 exceptions.add(new TypeException("Invalid casting type"));
00930 }
00931 variablesUsed.put(node, cast);
00932 currentType = cast;
00933 }
00934
00935
00936
00937
00938 public void caseAStrongObjectNavigation(AStrongObjectNavigation node) {
00939 String id = node.getId().toString().trim();
00940 if ("length".equals(id) && (currentType instanceof ArrayType)) {
00941 currentType = IntType.TYPE;
00942 } else if (currentType instanceof ClassOrInterfaceType) {
00943 try {
00944 Field f = ((ClassOrInterfaceType) currentType).getField(new Name(id));
00945 currentType = f.getType();
00946 variablesUsed.put(node, f);
00947 if (usedTypeNames.contains(((ANavigationExp) node.parent()).getExp())) {
00948 if (!f.isAccessible(type)) {
00949 exceptions.add(new TypeException("Field '"
00950 + currentType.getFullyQualifiedName() + "." + f.getName()
00951 + "' is from accessible from '" + type.getFullyQualifiedName()));
00952 currentType = VoidType.TYPE;
00953 }
00954 }
00955 } catch (Exception e) {
00956 exceptions.add(new TypeException("Field undefined"));
00957 currentType = VoidType.TYPE;
00958 }
00959 } else {
00960 exceptions.add(new TypeException("Not an object in field access"));
00961 currentType = VoidType.TYPE;
00962 }
00963 }
00964
00965
00966
00967
00968 public void caseAThisExp(AThisExp node) {
00969 if (isStatic) {
00970 exceptions.add(new BadPredicateDefinitionException("Cannot have " + node.getThis().toString() + "in non-static predicate"));
00971 currentType = NullType.TYPE;
00972 return;
00973 }
00974 variablesUsed.put(node, "this");
00975 if (annotation instanceof MethodDeclarationAnnotation) {
00976 try {
00977 currentType =
00978 ((MethodDeclarationAnnotation) annotation).getMethod().getDeclaringClassOrInterface();
00979 } catch (Exception e) {}
00980 } else if (annotation instanceof ConstructorDeclarationAnnotation) {
00981 try {
00982 currentType =
00983 ((ConstructorDeclarationAnnotation) annotation).getConstructor().getDeclaringClassOrInterface();
00984 } catch (Exception e) {}
00985 } else {
00986 currentType = type;
00987 }
00988 }
00989
00990
00991
00992
00993 public void caseATrueLiteral(ATrueLiteral node) {
00994 currentType = BooleanType.TYPE;
00995 }
00996
00997
00998
00999
01000 public void caseAUnit(AUnit node) {
01001 if(node.getName() != null) {
01002 predName = new Name(node.getName().toString()).toString().trim();
01003 } else {
01004 if (annotation != null) {
01005 if (annotation instanceof MethodDeclarationAnnotation) {
01006 MethodDeclarationAnnotation mda = (MethodDeclarationAnnotation) annotation;
01007 try {
01008 predName = mda.getMethod().getDeclaringClassOrInterface().getFullyQualifiedName()
01009 + "." + mda.getMethod().getName().toString();
01010 } catch (Exception e) {
01011 throw new RuntimeException("Fatal Error");
01012 }
01013 } else {
01014 ConstructorDeclarationAnnotation cda = (ConstructorDeclarationAnnotation) annotation;
01015 try {
01016 predName = cda.getConstructor().getDeclaringClassOrInterface().getFullyQualifiedName()
01017 + "." + cda.getConstructor().getDeclaringClassOrInterface().getName().getLastIdentifier();
01018 } catch (Exception e) {
01019 throw new RuntimeException("Fatal Error");
01020 }
01021 }
01022 } else {
01023 predName = type.getFullyQualifiedName();
01024 }
01025 }
01026 super.caseAUnit(node);
01027 }
01028
01029
01030
01031 public void check() {
01032 node.apply(this);
01033 }
01034
01035
01036
01037
01038 private Hashtable getDeclaredLocals() {
01039 if (mode == LOCATION) {
01040 Hashtable visibleLocals;
01041 if (annotation instanceof MethodDeclarationAnnotation) {
01042 visibleLocals = ((MethodDeclarationAnnotation) annotation).getParameterLocals();
01043 } else {
01044 visibleLocals = ((ConstructorDeclarationAnnotation) annotation).getParameterLocals();
01045 }
01046 for (Enumeration e = currentAnnotation.getDeclaredLocalVariables().elements();
01047 e.hasMoreElements();) {
01048 Local l = (Local) e.nextElement();
01049 visibleLocals.put(l.getName().trim(), l);
01050 }
01051 return visibleLocals;
01052 } else if (mode != EXP) {
01053 if (annotation instanceof MethodDeclarationAnnotation) {
01054 return ((MethodDeclarationAnnotation) annotation).getParameterLocals();
01055 } else {
01056 return ((ConstructorDeclarationAnnotation) annotation).getParameterLocals();
01057 }
01058 } else {
01059 return new Hashtable();
01060 }
01061 }
01062
01063
01064
01065
01066
01067
01068 private Type getIntegralType(Type leftType, Type rightType) {
01069 if (!(leftType instanceof IntegralType) || !(rightType instanceof IntegralType))
01070 return null;
01071 if ((leftType == LongType.TYPE) || (rightType == LongType.TYPE))
01072 return LongType.TYPE;
01073 else if ((leftType instanceof IntegralType) || (rightType instanceof IntegralType))
01074 return IntType.TYPE;
01075 else return null;
01076 }
01077
01078
01079
01080
01081
01082
01083 private Type getNumericType(Type leftType, Type rightType) {
01084 if (!(leftType instanceof NumericType) || !(rightType instanceof NumericType))
01085 return null;
01086 if ((leftType == LongType.TYPE) || (rightType == LongType.TYPE))
01087 return LongType.TYPE;
01088 else if ((leftType == FloatType.TYPE) || (rightType == FloatType.TYPE))
01089 return FloatType.TYPE;
01090 else if ((leftType == DoubleType.TYPE) || (rightType == DoubleType.TYPE))
01091 return DoubleType.TYPE;
01092 else if ((leftType instanceof IntegralType) || (rightType instanceof IntegralType))
01093 return IntType.TYPE;
01094 else return null;
01095 }
01096 }