001: /* Soot - a J*va Optimization Framework
002: * Copyright (C) 2003 John Jorgensen
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Library General Public
006: * License as published by the Free Software Foundation; either
007: * version 2 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Library General Public License for more details.
013: *
014: * You should have received a copy of the GNU Library General Public
015: * License along with this library; if not, write to the
016: * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
017: * Boston, MA 02111-1307, USA.
018: */
019:
020: package soot.toolkits.exceptions;
021:
022: import java.util.Iterator;
023: import soot.*;
024: import soot.baf.*;
025: import soot.jimple.*;
026: import soot.grimp.*;
027: import soot.shimple.ShimpleValueSwitch;
028: import soot.shimple.PhiExpr;
029:
030: /**
031: * A {@link ThrowAnalysis} which returns the set of runtime exceptions
032: * and errors that might be thrown by the bytecode instructions
033: * represented by a unit, as indicated by the Java Virtual Machine
034: * specification. I.e. this analysis is based entirely on the
035: * “opcode” of the unit, the types of its arguments, and
036: * the values of constant arguments.
037: *
038: * <p>The <code>mightThrow</code> methods could be declared static.
039: * They are left virtual to facilitate testing. For example,
040: * to verify that the expressions in a method call are actually being
041: * examined, a test case can override the mightThrow(SootMethod)
042: * with an implementation which returns the empty set instead of
043: * all possible exceptions.
044: */
045: public class UnitThrowAnalysis extends AbstractThrowAnalysis {
046:
047: // Cache the response to mightThrowImplicitly():
048: private final ThrowableSet implicitThrowExceptions = ThrowableSet.Manager
049: .v().VM_ERRORS.add(
050: ThrowableSet.Manager.v().NULL_POINTER_EXCEPTION).add(
051: ThrowableSet.Manager.v().ILLEGAL_MONITOR_STATE_EXCEPTION);
052:
053: /**
054: * Constructs a <code>UnitThrowAnalysis</code> for inclusion in
055: * Soot's global variable manager, {@link G}.
056: *
057: * @param g guarantees that the constructor may only be called
058: * from {@link Singletons}.
059: */
060: public UnitThrowAnalysis(Singletons.Global g) {
061: }
062:
063: /**
064: * A protected constructor for use by unit tests.
065: */
066: protected UnitThrowAnalysis() {
067: }
068:
069: /**
070: * Returns the single instance of <code>UnitThrowAnalysis</code>.
071: *
072: * @return Soot's <code>UnitThrowAnalysis</code>.
073: */
074: public static UnitThrowAnalysis v() {
075: return G.v().soot_toolkits_exceptions_UnitThrowAnalysis();
076: }
077:
078: public ThrowableSet mightThrow(Unit u) {
079: UnitSwitch sw = new UnitSwitch();
080: u.apply(sw);
081: return sw.getResult();
082: }
083:
084: public ThrowableSet mightThrowImplicitly(ThrowInst t) {
085: return implicitThrowExceptions;
086: }
087:
088: public ThrowableSet mightThrowImplicitly(ThrowStmt t) {
089: return implicitThrowExceptions;
090: }
091:
092: ThrowableSet mightThrow(Value v) {
093: ValueSwitch sw = new ValueSwitch();
094: v.apply(sw);
095: return sw.getResult();
096: }
097:
098: /**
099: * Returns the set of types that might be thrown as a result of
100: * calling the specified method.
101: *
102: * @param m method whose exceptions are to be returned.
103: *
104: * @return a representation of the set of {@link
105: * java.lang.Throwable Throwable} types that <code>m</code> might
106: * throw.
107: */
108: ThrowableSet mightThrow(SootMethod m) {
109: // In the absence of an interprocedural analysis,
110: // m could throw anything.
111: return ThrowableSet.Manager.v().ALL_THROWABLES;
112: }
113:
114: private static final IntConstant INT_CONSTANT_ZERO = IntConstant
115: .v(0);
116: private static final LongConstant LONG_CONSTANT_ZERO = LongConstant
117: .v(0);
118:
119: protected class UnitSwitch implements InstSwitch, StmtSwitch {
120:
121: private final ThrowableSet.Manager mgr = ThrowableSet.Manager
122: .v();
123:
124: // Asynchronous errors are always possible:
125: private ThrowableSet result = mgr.VM_ERRORS;
126:
127: ThrowableSet getResult() {
128: return result;
129: }
130:
131: public void caseReturnVoidInst(ReturnVoidInst i) {
132: result = result.add(mgr.ILLEGAL_MONITOR_STATE_EXCEPTION);
133: }
134:
135: public void caseReturnInst(ReturnInst i) {
136: result = result.add(mgr.ILLEGAL_MONITOR_STATE_EXCEPTION);
137: }
138:
139: public void caseNopInst(NopInst i) {
140: }
141:
142: public void caseGotoInst(GotoInst i) {
143: }
144:
145: public void caseJSRInst(JSRInst i) {
146: }
147:
148: public void casePushInst(PushInst i) {
149: }
150:
151: public void casePopInst(PopInst i) {
152: }
153:
154: public void caseIdentityInst(IdentityInst i) {
155: }
156:
157: public void caseStoreInst(StoreInst i) {
158: }
159:
160: public void caseLoadInst(LoadInst i) {
161: }
162:
163: public void caseArrayWriteInst(ArrayWriteInst i) {
164: result = result.add(mgr.NULL_POINTER_EXCEPTION);
165: result = result
166: .add(mgr.ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION);
167: if (i.getOpType() instanceof RefType) {
168: result = result.add(mgr.ARRAY_STORE_EXCEPTION);
169: }
170: }
171:
172: public void caseArrayReadInst(ArrayReadInst i) {
173: result = result.add(mgr.NULL_POINTER_EXCEPTION);
174: result = result
175: .add(mgr.ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION);
176: }
177:
178: public void caseIfNullInst(IfNullInst i) {
179: }
180:
181: public void caseIfNonNullInst(IfNonNullInst i) {
182: }
183:
184: public void caseIfEqInst(IfEqInst i) {
185: }
186:
187: public void caseIfNeInst(IfNeInst i) {
188: }
189:
190: public void caseIfGtInst(IfGtInst i) {
191: }
192:
193: public void caseIfGeInst(IfGeInst i) {
194: }
195:
196: public void caseIfLtInst(IfLtInst i) {
197: }
198:
199: public void caseIfLeInst(IfLeInst i) {
200: }
201:
202: public void caseIfCmpEqInst(IfCmpEqInst i) {
203: }
204:
205: public void caseIfCmpNeInst(IfCmpNeInst i) {
206: }
207:
208: public void caseIfCmpGtInst(IfCmpGtInst i) {
209: }
210:
211: public void caseIfCmpGeInst(IfCmpGeInst i) {
212: }
213:
214: public void caseIfCmpLtInst(IfCmpLtInst i) {
215: }
216:
217: public void caseIfCmpLeInst(IfCmpLeInst i) {
218: }
219:
220: public void caseStaticGetInst(StaticGetInst i) {
221: result = result.add(mgr.INITIALIZATION_ERRORS);
222: }
223:
224: public void caseStaticPutInst(StaticPutInst i) {
225: result = result.add(mgr.INITIALIZATION_ERRORS);
226: }
227:
228: public void caseFieldGetInst(FieldGetInst i) {
229: result = result.add(mgr.RESOLVE_FIELD_ERRORS);
230: result = result.add(mgr.NULL_POINTER_EXCEPTION);
231: }
232:
233: public void caseFieldPutInst(FieldPutInst i) {
234: result = result.add(mgr.RESOLVE_FIELD_ERRORS);
235: result = result.add(mgr.NULL_POINTER_EXCEPTION);
236: }
237:
238: public void caseInstanceCastInst(InstanceCastInst i) {
239: result = result.add(mgr.RESOLVE_CLASS_ERRORS);
240: result = result.add(mgr.CLASS_CAST_EXCEPTION);
241: }
242:
243: public void caseInstanceOfInst(InstanceOfInst i) {
244: result = result.add(mgr.RESOLVE_CLASS_ERRORS);
245: }
246:
247: public void casePrimitiveCastInst(PrimitiveCastInst i) {
248: }
249:
250: public void caseStaticInvokeInst(StaticInvokeInst i) {
251: result = result.add(mgr.INITIALIZATION_ERRORS);
252: result = result.add(mightThrow(i.getMethod()));
253: }
254:
255: public void caseVirtualInvokeInst(VirtualInvokeInst i) {
256: result = result.add(mgr.RESOLVE_METHOD_ERRORS);
257: result = result.add(mgr.NULL_POINTER_EXCEPTION);
258: result = result.add(mightThrow(i.getMethod()));
259: }
260:
261: public void caseInterfaceInvokeInst(InterfaceInvokeInst i) {
262: result = result.add(mgr.RESOLVE_METHOD_ERRORS);
263: result = result.add(mgr.NULL_POINTER_EXCEPTION);
264: result = result.add(mightThrow(i.getMethod()));
265: }
266:
267: public void caseSpecialInvokeInst(SpecialInvokeInst i) {
268: result = result.add(mgr.RESOLVE_METHOD_ERRORS);
269: result = result.add(mgr.NULL_POINTER_EXCEPTION);
270: result = result.add(mightThrow(i.getMethod()));
271: }
272:
273: public void caseThrowInst(ThrowInst i) {
274: result = mightThrowImplicitly(i);
275: result = result.add(mightThrowExplicitly(i));
276: }
277:
278: public void caseAddInst(AddInst i) {
279: }
280:
281: public void caseAndInst(AndInst i) {
282: }
283:
284: public void caseOrInst(OrInst i) {
285: }
286:
287: public void caseXorInst(XorInst i) {
288: }
289:
290: public void caseArrayLengthInst(ArrayLengthInst i) {
291: result = result.add(mgr.NULL_POINTER_EXCEPTION);
292: }
293:
294: public void caseCmpInst(CmpInst i) {
295: }
296:
297: public void caseCmpgInst(CmpgInst i) {
298: }
299:
300: public void caseCmplInst(CmplInst i) {
301: }
302:
303: public void caseDivInst(DivInst i) {
304: if (i.getOpType() instanceof IntegerType
305: || i.getOpType() == LongType.v()) {
306: result = result.add(mgr.ARITHMETIC_EXCEPTION);
307: }
308: }
309:
310: public void caseIncInst(IncInst i) {
311: }
312:
313: public void caseMulInst(MulInst i) {
314: }
315:
316: public void caseRemInst(RemInst i) {
317: if (i.getOpType() instanceof IntegerType
318: || i.getOpType() == LongType.v()) {
319: result = result.add(mgr.ARITHMETIC_EXCEPTION);
320: }
321: }
322:
323: public void caseSubInst(SubInst i) {
324: }
325:
326: public void caseShlInst(ShlInst i) {
327: }
328:
329: public void caseShrInst(ShrInst i) {
330: }
331:
332: public void caseUshrInst(UshrInst i) {
333: }
334:
335: public void caseNewInst(NewInst i) {
336: result = result.add(mgr.INITIALIZATION_ERRORS);
337: }
338:
339: public void caseNegInst(NegInst i) {
340: }
341:
342: public void caseSwapInst(SwapInst i) {
343: }
344:
345: public void caseDup1Inst(Dup1Inst i) {
346: }
347:
348: public void caseDup2Inst(Dup2Inst i) {
349: }
350:
351: public void caseDup1_x1Inst(Dup1_x1Inst i) {
352: }
353:
354: public void caseDup1_x2Inst(Dup1_x2Inst i) {
355: }
356:
357: public void caseDup2_x1Inst(Dup2_x1Inst i) {
358: }
359:
360: public void caseDup2_x2Inst(Dup2_x2Inst i) {
361: }
362:
363: public void caseNewArrayInst(NewArrayInst i) {
364: result = result.add(mgr.RESOLVE_CLASS_ERRORS); // Could be omitted for primitive arrays.
365: result = result.add(mgr.NEGATIVE_ARRAY_SIZE_EXCEPTION);
366: }
367:
368: public void caseNewMultiArrayInst(NewMultiArrayInst i) {
369: result = result.add(mgr.RESOLVE_CLASS_ERRORS);
370: result = result.add(mgr.NEGATIVE_ARRAY_SIZE_EXCEPTION);
371: }
372:
373: public void caseLookupSwitchInst(LookupSwitchInst i) {
374: }
375:
376: public void caseTableSwitchInst(TableSwitchInst i) {
377: }
378:
379: public void caseEnterMonitorInst(EnterMonitorInst i) {
380: result = result.add(mgr.NULL_POINTER_EXCEPTION);
381: }
382:
383: public void caseExitMonitorInst(ExitMonitorInst i) {
384: result = result.add(mgr.ILLEGAL_MONITOR_STATE_EXCEPTION);
385: result = result.add(mgr.NULL_POINTER_EXCEPTION);
386: }
387:
388: public void caseAssignStmt(AssignStmt s) {
389: Value lhs = s.getLeftOp();
390: if (lhs instanceof ArrayRef
391: && (lhs.getType() instanceof UnknownType || lhs
392: .getType() instanceof RefType)) {
393: // This corresponds to an aastore byte code.
394: result = result.add(mgr.ARRAY_STORE_EXCEPTION);
395: }
396: result = result.add(mightThrow(s.getLeftOp()));
397: result = result.add(mightThrow(s.getRightOp()));
398: }
399:
400: public void caseBreakpointStmt(BreakpointStmt s) {
401: }
402:
403: public void caseEnterMonitorStmt(EnterMonitorStmt s) {
404: result = result.add(mgr.NULL_POINTER_EXCEPTION);
405: result = result.add(mightThrow(s.getOp()));
406: }
407:
408: public void caseExitMonitorStmt(ExitMonitorStmt s) {
409: result = result.add(mgr.ILLEGAL_MONITOR_STATE_EXCEPTION);
410: result = result.add(mgr.NULL_POINTER_EXCEPTION);
411: result = result.add(mightThrow(s.getOp()));
412: }
413:
414: public void caseGotoStmt(GotoStmt s) {
415: }
416:
417: public void caseIdentityStmt(IdentityStmt s) {
418: }
419:
420: // Perhaps IdentityStmt shouldn't even return VM_ERRORS,
421: // since it corresponds to no bytecode instructions whatsoever.
422:
423: public void caseIfStmt(IfStmt s) {
424: result = result.add(mightThrow(s.getCondition()));
425: }
426:
427: public void caseInvokeStmt(InvokeStmt s) {
428: result = result.add(mightThrow(s.getInvokeExpr()));
429: }
430:
431: public void caseLookupSwitchStmt(LookupSwitchStmt s) {
432: result = result.add(mightThrow(s.getKey()));
433: }
434:
435: public void caseNopStmt(NopStmt s) {
436: }
437:
438: public void caseRetStmt(RetStmt s) {
439: // Soot should never produce any RetStmt, since
440: // it implements jsr with gotos.
441: }
442:
443: public void caseReturnStmt(ReturnStmt s) {
444: result = result.add(mgr.ILLEGAL_MONITOR_STATE_EXCEPTION);
445: result = result.add(mightThrow(s.getOp()));
446: }
447:
448: public void caseReturnVoidStmt(ReturnVoidStmt s) {
449: result = result.add(mgr.ILLEGAL_MONITOR_STATE_EXCEPTION);
450: }
451:
452: public void caseTableSwitchStmt(TableSwitchStmt s) {
453: result = result.add(mightThrow(s.getKey()));
454: }
455:
456: public void caseThrowStmt(ThrowStmt s) {
457: result = mightThrowImplicitly(s);
458: result = result.add(mightThrowExplicitly(s));
459: }
460:
461: public void defaultCase(Object obj) {
462: }
463: }
464:
465: protected class ValueSwitch implements GrimpValueSwitch,
466: ShimpleValueSwitch {
467:
468: private final ThrowableSet.Manager mgr = ThrowableSet.Manager
469: .v();
470:
471: // Asynchronous errors are always possible:
472: private ThrowableSet result = mgr.VM_ERRORS;
473:
474: ThrowableSet getResult() {
475: return result;
476: }
477:
478: // Declared by ConstantSwitch interface:
479:
480: public void caseDoubleConstant(DoubleConstant c) {
481: }
482:
483: public void caseFloatConstant(FloatConstant c) {
484: }
485:
486: public void caseIntConstant(IntConstant c) {
487: }
488:
489: public void caseLongConstant(LongConstant c) {
490: }
491:
492: public void caseNullConstant(NullConstant c) {
493: }
494:
495: public void caseStringConstant(StringConstant c) {
496: }
497:
498: public void caseClassConstant(ClassConstant c) {
499: }
500:
501: // Declared by ExprSwitch interface:
502:
503: public void caseAddExpr(AddExpr expr) {
504: caseBinopExpr(expr);
505: }
506:
507: public void caseAndExpr(AndExpr expr) {
508: caseBinopExpr(expr);
509: }
510:
511: public void caseCmpExpr(CmpExpr expr) {
512: caseBinopExpr(expr);
513: }
514:
515: public void caseCmpgExpr(CmpgExpr expr) {
516: caseBinopExpr(expr);
517: }
518:
519: public void caseCmplExpr(CmplExpr expr) {
520: caseBinopExpr(expr);
521: }
522:
523: public void caseDivExpr(DivExpr expr) {
524: caseBinopDivExpr(expr);
525: }
526:
527: public void caseEqExpr(EqExpr expr) {
528: caseBinopExpr(expr);
529: }
530:
531: public void caseNeExpr(NeExpr expr) {
532: caseBinopExpr(expr);
533: }
534:
535: public void caseGeExpr(GeExpr expr) {
536: caseBinopExpr(expr);
537: }
538:
539: public void caseGtExpr(GtExpr expr) {
540: caseBinopExpr(expr);
541: }
542:
543: public void caseLeExpr(LeExpr expr) {
544: caseBinopExpr(expr);
545: }
546:
547: public void caseLtExpr(LtExpr expr) {
548: caseBinopExpr(expr);
549: }
550:
551: public void caseMulExpr(MulExpr expr) {
552: caseBinopExpr(expr);
553: }
554:
555: public void caseOrExpr(OrExpr expr) {
556: caseBinopExpr(expr);
557: }
558:
559: public void caseRemExpr(RemExpr expr) {
560: caseBinopDivExpr(expr);
561: }
562:
563: public void caseShlExpr(ShlExpr expr) {
564: caseBinopExpr(expr);
565: }
566:
567: public void caseShrExpr(ShrExpr expr) {
568: caseBinopExpr(expr);
569: }
570:
571: public void caseUshrExpr(UshrExpr expr) {
572: caseBinopExpr(expr);
573: }
574:
575: public void caseSubExpr(SubExpr expr) {
576: caseBinopExpr(expr);
577: }
578:
579: public void caseXorExpr(XorExpr expr) {
580: caseBinopExpr(expr);
581: }
582:
583: public void caseInterfaceInvokeExpr(InterfaceInvokeExpr expr) {
584: caseInstanceInvokeExpr(expr);
585: }
586:
587: public void caseSpecialInvokeExpr(SpecialInvokeExpr expr) {
588: caseInstanceInvokeExpr(expr);
589: }
590:
591: public void caseStaticInvokeExpr(StaticInvokeExpr expr) {
592: result = result.add(mgr.INITIALIZATION_ERRORS);
593: for (int i = 0; i < expr.getArgCount(); i++) {
594: result = result.add(mightThrow(expr.getArg(i)));
595: }
596: result = result.add(mightThrow(expr.getMethod()));
597: }
598:
599: public void caseVirtualInvokeExpr(VirtualInvokeExpr expr) {
600: caseInstanceInvokeExpr(expr);
601: }
602:
603: public void caseCastExpr(CastExpr expr) {
604: result = result.add(mgr.RESOLVE_CLASS_ERRORS);
605: Type fromType = expr.getOp().getType();
606: Type toType = expr.getCastType();
607: if (toType instanceof RefLikeType) {
608: // fromType might still be unknown when we are called,
609: // but toType will have a value.
610: FastHierarchy h = Scene.v().getOrMakeFastHierarchy();
611: if (fromType == null
612: || fromType instanceof UnknownType
613: || ((!(fromType instanceof NullType)) && (!h
614: .canStoreType(fromType, toType)))) {
615: result = result.add(mgr.CLASS_CAST_EXCEPTION);
616: }
617: }
618: result = result.add(mightThrow(expr.getOp()));
619: }
620:
621: public void caseInstanceOfExpr(InstanceOfExpr expr) {
622: result = result.add(mgr.RESOLVE_CLASS_ERRORS);
623: result = result.add(mightThrow(expr.getOp()));
624: }
625:
626: public void caseNewArrayExpr(NewArrayExpr expr) {
627: if (expr.getBaseType() instanceof RefLikeType) {
628: result = result.add(mgr.RESOLVE_CLASS_ERRORS);
629: }
630: Value count = expr.getSize();
631: if ((!(count instanceof IntConstant))
632: || (((IntConstant) count)
633: .lessThan(INT_CONSTANT_ZERO)
634: .equals(INT_CONSTANT_ZERO))) {
635: result = result.add(mgr.NEGATIVE_ARRAY_SIZE_EXCEPTION);
636: }
637: result = result.add(mightThrow(count));
638: }
639:
640: public void caseNewMultiArrayExpr(NewMultiArrayExpr expr) {
641: result = result.add(mgr.RESOLVE_CLASS_ERRORS);
642: for (int i = 0; i < expr.getSizeCount(); i++) {
643: Value count = expr.getSize(i);
644: if ((!(count instanceof IntConstant))
645: || (((IntConstant) count)
646: .lessThan(INT_CONSTANT_ZERO)
647: .equals(INT_CONSTANT_ZERO))) {
648: result = result
649: .add(mgr.NEGATIVE_ARRAY_SIZE_EXCEPTION);
650: }
651: result = result.add(mightThrow(count));
652: }
653: }
654:
655: public void caseNewExpr(NewExpr expr) {
656: result = result.add(mgr.INITIALIZATION_ERRORS);
657: for (Iterator i = expr.getUseBoxes().iterator(); i
658: .hasNext();) {
659: ValueBox box = (ValueBox) i.next();
660: result = result.add(mightThrow(box.getValue()));
661: }
662: }
663:
664: public void caseLengthExpr(LengthExpr expr) {
665: result = result.add(mgr.NULL_POINTER_EXCEPTION);
666: result = result.add(mightThrow(expr.getOp()));
667: }
668:
669: public void caseNegExpr(NegExpr expr) {
670: result = result.add(mightThrow(expr.getOp()));
671: }
672:
673: // Declared by RefSwitch interface:
674:
675: public void caseArrayRef(ArrayRef ref) {
676: result = result.add(mgr.NULL_POINTER_EXCEPTION);
677: result = result
678: .add(mgr.ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION);
679: result = result.add(mightThrow(ref.getBase()));
680: result = result.add(mightThrow(ref.getIndex()));
681: }
682:
683: public void caseStaticFieldRef(StaticFieldRef ref) {
684: result = result.add(mgr.INITIALIZATION_ERRORS);
685: }
686:
687: public void caseInstanceFieldRef(InstanceFieldRef ref) {
688: result = result.add(mgr.RESOLVE_FIELD_ERRORS);
689: result = result.add(mgr.NULL_POINTER_EXCEPTION);
690: result = result.add(mightThrow(ref.getBase()));
691: }
692:
693: public void caseParameterRef(ParameterRef v) {
694: }
695:
696: public void caseCaughtExceptionRef(CaughtExceptionRef v) {
697: }
698:
699: public void caseThisRef(ThisRef v) {
700: }
701:
702: public void caseLocal(Local l) {
703: }
704:
705: public void caseNewInvokeExpr(NewInvokeExpr e) {
706: caseStaticInvokeExpr(e);
707: }
708:
709: public void casePhiExpr(PhiExpr e) {
710: for (Iterator i = e.getUseBoxes().iterator(); i.hasNext();) {
711: ValueBox box = (ValueBox) i.next();
712: result = result.add(mightThrow(box.getValue()));
713: }
714: }
715:
716: public void defaultCase(Object obj) {
717: }
718:
719: // The remaining cases are not declared by GrimpValueSwitch,
720: // but are used to factor out code common to several cases.
721:
722: private void caseBinopExpr(BinopExpr expr) {
723: result = result.add(mightThrow(expr.getOp1()));
724: result = result.add(mightThrow(expr.getOp2()));
725: }
726:
727: private void caseBinopDivExpr(BinopExpr expr) {
728: // Factors out code common to caseDivExpr and caseRemExpr.
729: // The checks against constant divisors would perhaps be
730: // better performed in a later pass, post-constant-propagation.
731: Value divisor = expr.getOp2();
732: Type divisorType = divisor.getType();
733: if (divisorType instanceof UnknownType) {
734: result = result.add(mgr.ARITHMETIC_EXCEPTION);
735: } else if ((divisorType instanceof IntegerType)
736: && ((!(divisor instanceof IntConstant)) || (((IntConstant) divisor)
737: .equals(INT_CONSTANT_ZERO)))) {
738: result = result.add(mgr.ARITHMETIC_EXCEPTION);
739: } else if ((divisorType == LongType.v())
740: && ((!(divisor instanceof LongConstant)) || (((LongConstant) divisor)
741: .equals(LONG_CONSTANT_ZERO)))) {
742: result = result.add(mgr.ARITHMETIC_EXCEPTION);
743: }
744: caseBinopExpr(expr);
745: }
746:
747: private void caseInstanceInvokeExpr(InstanceInvokeExpr expr) {
748: result = result.add(mgr.RESOLVE_METHOD_ERRORS);
749: result = result.add(mgr.NULL_POINTER_EXCEPTION);
750: for (int i = 0; i < expr.getArgCount(); i++) {
751: result = result.add(mightThrow(expr.getArg(i)));
752: }
753: result = result.add(mightThrow(expr.getBase()));
754: result = result.add(mightThrow(expr.getMethod()));
755: }
756: }
757: }
|