001: /* Soot - a J*va Optimization Framework
002: * Copyright (C) 1997-1999 Raja Vallee-Rai
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2.1 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: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser 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: /*
021: * Modified by the Sable Research Group and others 1997-1999.
022: * See the 'credits' file distributed with Soot for the complete list of
023: * contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot)
024: */
025:
026: package soot;
027:
028: import java.io.ByteArrayOutputStream;
029: import java.io.OutputStreamWriter;
030: import java.io.PrintWriter;
031: import java.io.Serializable;
032: import java.util.ArrayList;
033: import java.util.HashMap;
034: import java.util.Iterator;
035: import java.util.List;
036: import java.util.Map;
037:
038: import soot.jimple.CaughtExceptionRef;
039: import soot.jimple.DefinitionStmt;
040: import soot.jimple.IdentityStmt;
041: import soot.jimple.InstanceInvokeExpr;
042: import soot.jimple.InvokeExpr;
043: import soot.jimple.InvokeStmt;
044: import soot.jimple.ParameterRef;
045: import soot.jimple.ThisRef;
046: import soot.options.Options;
047: import soot.tagkit.AbstractHost;
048: import soot.tagkit.CodeAttribute;
049: import soot.tagkit.Tag;
050: import soot.toolkits.exceptions.PedanticThrowAnalysis;
051: import soot.toolkits.graph.ExceptionalUnitGraph;
052: import soot.toolkits.graph.UnitGraph;
053: import soot.toolkits.scalar.FlowSet;
054: import soot.toolkits.scalar.InitAnalysis;
055: import soot.toolkits.scalar.LocalDefs;
056: import soot.toolkits.scalar.SimpleLiveLocals;
057: import soot.toolkits.scalar.SmartLocalDefs;
058: import soot.util.Chain;
059: import soot.util.EscapedWriter;
060: import soot.util.HashChain;
061:
062: /**
063: * Abstract base class that models the body (code attribute) of a Java method.
064: * Classes that implement an Intermediate Representation for a method body should subclass it.
065: * In particular the classes GrimpBody, JimpleBody and BafBody all extend this
066: * class. This class provides methods that are common to any IR, such as methods
067: * to get the body's units (statements), traps, and locals.
068: *
069: * @see soot.grimp.GrimpBody
070: * @see soot.jimple.JimpleBody
071: * @see soot.baf.BafBody
072: */
073: public abstract class Body extends AbstractHost implements Serializable {
074: /** The method associated with this Body. */
075: protected transient SootMethod method = null;
076:
077: /** The chain of locals for this Body. */
078: protected Chain<Local> localChain = new HashChain<Local>();
079:
080: /** The chain of traps for this Body. */
081: protected Chain<Trap> trapChain = new HashChain<Trap>();
082:
083: /** The chain of units for this Body. */
084: protected PatchingChain<Unit> unitChain = new PatchingChain<Unit>(
085: new HashChain<Unit>());
086:
087: /** Creates a deep copy of this Body. */
088: abstract public Object clone();
089:
090: /** Creates a Body associated to the given method. Used by subclasses during initialization.
091: * Creation of a Body is triggered by e.g. Jimple.v().newBody(options).
092: */
093: protected Body(SootMethod m) {
094: this .method = m;
095: }
096:
097: /** Creates an extremely empty Body. The Body is not associated to any method. */
098: protected Body() {
099: }
100:
101: /**
102: * Returns the method associated with this Body.
103: * @return the method that owns this body.
104: */
105: public SootMethod getMethod() {
106: if (method == null)
107: throw new RuntimeException("no method associated w/ body");
108: return method;
109: }
110:
111: /**
112: * Sets the method associated with this Body.
113: * @param method the method that owns this body.
114: *
115: */
116: public void setMethod(SootMethod method) {
117: this .method = method;
118: }
119:
120: /** Returns the number of locals declared in this body. */
121: public int getLocalCount() {
122: return localChain.size();
123: }
124:
125: /** Copies the contents of the given Body into this one. */
126: public Map<Object, Object> importBodyContentsFrom(Body b) {
127: HashMap<Object, Object> bindings = new HashMap<Object, Object>();
128:
129: {
130: Iterator<Unit> it = b.getUnits().iterator();
131:
132: // Clone units in body's statement list
133: while (it.hasNext()) {
134: Unit original = it.next();
135: Unit copy = (Unit) original.clone();
136:
137: copy.addAllTagsOf(original);
138:
139: // Add cloned unit to our unitChain.
140: unitChain.addLast(copy);
141:
142: // Build old <-> new map to be able to patch up references to other units
143: // within the cloned units. (these are still refering to the original
144: // unit objects).
145: bindings.put(original, copy);
146: }
147: }
148:
149: {
150: // Clone trap units.
151: Iterator<Trap> it = b.getTraps().iterator();
152: while (it.hasNext()) {
153: Trap original = it.next();
154: Trap copy = (Trap) original.clone();
155:
156: // Add cloned unit to our trap list.
157: trapChain.addLast(copy);
158:
159: // Store old <-> new mapping.
160: bindings.put(original, copy);
161: }
162: }
163:
164: {
165: // Clone local units.
166: Iterator<Local> it = b.getLocals().iterator();
167: while (it.hasNext()) {
168: Local original = it.next();
169: Local copy = (Local) original.clone();
170:
171: // Add cloned unit to our trap list.
172: localChain.addLast(copy);
173:
174: // Build old <-> new mapping.
175: bindings.put(original, copy);
176: }
177: }
178:
179: {
180: // Patch up references within units using our (old <-> new) map.
181: Iterator<UnitBox> it = getAllUnitBoxes().iterator();
182: while (it.hasNext()) {
183: UnitBox box = it.next();
184: Unit newObject, oldObject = box.getUnit();
185:
186: // if we have a reference to an old object, replace it
187: // it's clone.
188: if ((newObject = (Unit) bindings.get(oldObject)) != null)
189: box.setUnit(newObject);
190:
191: }
192: }
193:
194: {
195: // backpatching all local variables.
196: Iterator<ValueBox> it = getUseBoxes().iterator();
197: while (it.hasNext()) {
198: ValueBox vb = it.next();
199: if (vb.getValue() instanceof Local)
200: vb.setValue((Value) bindings.get(vb.getValue()));
201: }
202: it = getDefBoxes().iterator();
203: while (it.hasNext()) {
204: ValueBox vb = it.next();
205: if (vb.getValue() instanceof Local)
206: vb.setValue((Value) bindings.get(vb.getValue()));
207: }
208: }
209: return bindings;
210: }
211:
212: /** Verifies a few sanity conditions on the contents on this body. */
213: public void validate() {
214: //System.out.println("body: "+this.getUnits());
215: validateLocals();
216: validateTraps();
217: validateUnitBoxes();
218: if (Options.v().debug() || Options.v().validate()) {
219: validateUses();
220: validateValueBoxes();
221: checkInit();
222: checkTypes();
223: checkLocals();
224: }
225: }
226:
227: /** Verifies that a ValueBox is not used in more than one place. */
228: public void validateValueBoxes() {
229: List<ValueBox> l = getUseAndDefBoxes();
230: for (int i = 0; i < l.size(); i++) {
231: for (int j = 0; j < l.size(); j++) {
232: if (i == j)
233: continue;
234: if (l.get(i) == l.get(j)) {
235: System.err.println("Aliased value box : "
236: + l.get(i) + " in " + getMethod());
237: for (Iterator<Unit> uIt = getUnits().iterator(); uIt
238: .hasNext();) {
239: final Unit u = uIt.next();
240: System.err.println("" + u);
241: }
242: throw new RuntimeException("Aliased value box : "
243: + l.get(i) + " in " + getMethod());
244: }
245: }
246: }
247: }
248:
249: /** Verifies that each Local of getUseAndDefBoxes() is in this body's locals Chain. */
250: public void validateLocals() {
251: Iterator<ValueBox> it = getUseBoxes().iterator();
252: while (it.hasNext()) {
253: validateLocal(it.next());
254: }
255: it = getDefBoxes().iterator();
256: while (it.hasNext()) {
257: validateLocal(it.next());
258: }
259: }
260:
261: private void validateLocal(ValueBox vb) {
262: Value value;
263: if ((value = vb.getValue()) instanceof Local) {
264: //System.out.println("localChain: "+localChain);
265: if (!localChain.contains(value))
266: throw new RuntimeException("Local not in chain : "
267: + value + " in " + getMethod());
268: }
269: }
270:
271: /** Verifies that the begin, end and handler units of each trap are in this body. */
272: public void validateTraps() {
273: Iterator<Trap> it = getTraps().iterator();
274: while (it.hasNext()) {
275: Trap t = it.next();
276: if (!unitChain.contains(t.getBeginUnit()))
277: throw new RuntimeException("begin not in chain"
278: + " in " + getMethod());
279:
280: if (!unitChain.contains(t.getEndUnit()))
281: throw new RuntimeException("end not in chain" + " in "
282: + getMethod());
283:
284: if (!unitChain.contains(t.getHandlerUnit()))
285: throw new RuntimeException("handler not in chain"
286: + " in " + getMethod());
287: }
288: }
289:
290: /** Verifies that the UnitBoxes of this Body all point to a Unit contained within this body. */
291: public void validateUnitBoxes() {
292: Iterator<UnitBox> it = getAllUnitBoxes().iterator();
293: while (it.hasNext()) {
294: UnitBox ub = it.next();
295: if (!unitChain.contains(ub.getUnit()))
296: throw new RuntimeException(
297: "Unitbox points outside unitChain! to unit : "
298: + ub.getUnit() + " in " + getMethod());
299: }
300: }
301:
302: /** Verifies that each use in this Body has a def. */
303: public void validateUses() {
304: UnitGraph g = new ExceptionalUnitGraph(this );
305: LocalDefs ld = new SmartLocalDefs(g, new SimpleLiveLocals(g));
306:
307: Iterator<Unit> unitsIt = getUnits().iterator();
308: while (unitsIt.hasNext()) {
309: Unit u = unitsIt.next();
310: Iterator<ValueBox> useBoxIt = u.getUseBoxes().iterator();
311: while (useBoxIt.hasNext()) {
312: Value v = (useBoxIt.next()).getValue();
313: if (v instanceof Local) {
314: // This throws an exception if there is
315: // no def already; we check anyhow.
316: List<Unit> l = ld.getDefsOfAt((Local) v, u);
317: if (l.size() == 0) {
318: for (Iterator<Unit> uuIt = getUnits()
319: .iterator(); uuIt.hasNext();) {
320: final Unit uu = uuIt.next();
321: System.err.println("" + uu);
322: }
323: throw new RuntimeException(
324: "no defs for value: " + v + "!"
325: + " in " + getMethod());
326: }
327: }
328: }
329: }
330: }
331:
332: /** Returns a backed chain of the locals declared in this Body. */
333: public Chain<Local> getLocals() {
334: return localChain;
335: }
336:
337: /** Returns a backed view of the traps found in this Body. */
338: public Chain<Trap> getTraps() {
339: return trapChain;
340: }
341:
342: /** Return LHS of the first identity stmt assigning from \@this. **/
343: public Local getThisLocal() {
344: Iterator<Unit> unitsIt = getUnits().iterator();
345:
346: while (unitsIt.hasNext()) {
347: Unit s = unitsIt.next();
348: if (s instanceof IdentityStmt
349: && ((IdentityStmt) s).getRightOp() instanceof ThisRef)
350: return (Local) (((IdentityStmt) s).getLeftOp());
351: }
352:
353: throw new RuntimeException("couldn't find identityref!"
354: + " in " + getMethod());
355: }
356:
357: /** Return LHS of the first identity stmt assigning from \@parameter i. **/
358: public Local getParameterLocal(int i) {
359: Iterator<Unit> unitsIt = getUnits().iterator();
360: while (unitsIt.hasNext()) {
361: Unit s = unitsIt.next();
362: if (s instanceof IdentityStmt
363: && ((IdentityStmt) s).getRightOp() instanceof ParameterRef) {
364: IdentityStmt is = (IdentityStmt) s;
365: ParameterRef pr = (ParameterRef) is.getRightOp();
366: if (pr.getIndex() == i)
367: return (Local) is.getLeftOp();
368: }
369: }
370:
371: throw new RuntimeException("couldn't find parameterref!"
372: + " in " + getMethod());
373: }
374:
375: /**
376: * Returns the Chain of Units that make up this body. The units are
377: * returned as a PatchingChain. The client can then manipulate the chain,
378: * adding and removing units, and the changes will be reflected in the body.
379: * Since a PatchingChain is returned the client need <i>not</i> worry about removing exception
380: * boundary units or otherwise corrupting the chain.
381: *
382: * @return the units in this Body
383: *
384: * @see PatchingChain
385: * @see Unit
386: */
387: public PatchingChain<Unit> getUnits() {
388: return unitChain;
389: }
390:
391: /**
392: * Returns the result of iterating through all Units in this body
393: * and querying them for their UnitBoxes. All UnitBoxes thus
394: * found are returned. Branching Units and statements which use
395: * PhiExpr will have UnitBoxes; a UnitBox contains a Unit that is
396: * either a target of a branch or is being used as a pointer to
397: * the end of a CFG block.
398: *
399: * <p> This method is typically used for pointer patching, eg when
400: * the unit chain is cloned.
401: *
402: * @return A list of all the UnitBoxes held by this body's units.
403: * @see UnitBox
404: * @see #getUnitBoxes(boolean)
405: * @see Unit#getUnitBoxes()
406: * @see soot.shimple.PhiExpr#getUnitBoxes()
407: **/
408: public List<UnitBox> getAllUnitBoxes() {
409: ArrayList<UnitBox> unitBoxList = new ArrayList<UnitBox>();
410: {
411: Iterator<Unit> it = unitChain.iterator();
412: while (it.hasNext()) {
413: Unit item = it.next();
414: unitBoxList.addAll(item.getUnitBoxes());
415: }
416: }
417:
418: {
419: Iterator<Trap> it = trapChain.iterator();
420: while (it.hasNext()) {
421: Trap item = it.next();
422: unitBoxList.addAll(item.getUnitBoxes());
423: }
424: }
425:
426: {
427: Iterator<Tag> it = getTags().iterator();
428: while (it.hasNext()) {
429: Tag t = it.next();
430: if (t instanceof CodeAttribute)
431: unitBoxList.addAll(((CodeAttribute) t)
432: .getUnitBoxes());
433: }
434: }
435:
436: return unitBoxList;
437: }
438:
439: /**
440: * If branchTarget is true, returns the result of iterating
441: * through all branching Units in this body and querying them for
442: * their UnitBoxes. These UnitBoxes contain Units that are the
443: * target of a branch. This is useful for, say, labeling blocks
444: * or updating the targets of branching statements.
445: *
446: * <p> If branchTarget is false, returns the result of iterating
447: * through the non-branching Units in this body and querying them
448: * for their UnitBoxes. Any such UnitBoxes (typically from
449: * PhiExpr) contain a Unit that indicates the end of a CFG block.
450: *
451: * @return a list of all the UnitBoxes held by this body's
452: * branching units.
453: *
454: * @see UnitBox
455: * @see #getAllUnitBoxes()
456: * @see Unit#getUnitBoxes()
457: * @see soot.shimple.PhiExpr#getUnitBoxes()
458: **/
459: public List<UnitBox> getUnitBoxes(boolean branchTarget) {
460: ArrayList<UnitBox> unitBoxList = new ArrayList<UnitBox>();
461: {
462: Iterator<Unit> it = unitChain.iterator();
463: while (it.hasNext()) {
464: Unit item = it.next();
465: if (branchTarget) {
466: if (item.branches())
467: unitBoxList.addAll(item.getUnitBoxes());
468: } else {
469: if (!item.branches())
470: unitBoxList.addAll(item.getUnitBoxes());
471: }
472: }
473: }
474:
475: {
476: Iterator<Trap> it = trapChain.iterator();
477: while (it.hasNext()) {
478: Trap item = it.next();
479: unitBoxList.addAll(item.getUnitBoxes());
480: }
481: }
482:
483: {
484: Iterator<Tag> it = getTags().iterator();
485: while (it.hasNext()) {
486: Tag t = it.next();
487: if (t instanceof CodeAttribute)
488: unitBoxList.addAll(((CodeAttribute) t)
489: .getUnitBoxes());
490: }
491: }
492:
493: return unitBoxList;
494: }
495:
496: /**
497: * Returns the result of iterating through all Units in this
498: * body and querying them for ValueBoxes used.
499: * All of the ValueBoxes found are then returned as a List.
500: *
501: * @return a list of all the ValueBoxes for the Values used this body's units.
502: *
503: * @see Value
504: * @see Unit#getUseBoxes
505: * @see ValueBox
506: * @see Value
507: *
508: */
509: public List<ValueBox> getUseBoxes() {
510: ArrayList<ValueBox> useBoxList = new ArrayList<ValueBox>();
511:
512: Iterator<Unit> it = unitChain.iterator();
513: while (it.hasNext()) {
514: Unit item = it.next();
515: useBoxList.addAll(item.getUseBoxes());
516: }
517: return useBoxList;
518: }
519:
520: /**
521: * Returns the result of iterating through all Units in this
522: * body and querying them for ValueBoxes defined.
523: * All of the ValueBoxes found are then returned as a List.
524: *
525: * @return a list of all the ValueBoxes for Values defined by this body's units.
526: *
527: * @see Value
528: * @see Unit#getDefBoxes
529: * @see ValueBox
530: * @see Value
531: */
532: public List<ValueBox> getDefBoxes() {
533: ArrayList<ValueBox> defBoxList = new ArrayList<ValueBox>();
534:
535: Iterator<Unit> it = unitChain.iterator();
536: while (it.hasNext()) {
537: Unit item = it.next();
538: defBoxList.addAll(item.getDefBoxes());
539: }
540: return defBoxList;
541: }
542:
543: /**
544: * Returns a list of boxes corresponding to Values
545: * either used or defined in any unit of this Body.
546: *
547: * @return a list of ValueBoxes for held by the body's Units.
548: *
549: * @see Value
550: * @see Unit#getUseAndDefBoxes
551: * @see ValueBox
552: * @see Value
553: */
554: public List<ValueBox> getUseAndDefBoxes() {
555: ArrayList<ValueBox> useAndDefBoxList = new ArrayList<ValueBox>();
556:
557: Iterator<Unit> it = unitChain.iterator();
558: while (it.hasNext()) {
559: Unit item = it.next();
560: useAndDefBoxList.addAll(item.getUseBoxes());
561: useAndDefBoxList.addAll(item.getDefBoxes());
562: }
563: return useAndDefBoxList;
564: }
565:
566: private void checkLocals() {
567: Chain<Local> locals = getLocals();
568:
569: Iterator<Local> it = locals.iterator();
570: while (it.hasNext()) {
571: Local l = it.next();
572: if (l.getType() instanceof VoidType)
573: throw new RuntimeException("Local " + l + " in "
574: + method + " defined with void type");
575: }
576: }
577:
578: private void checkTypes() {
579: Chain<Unit> units = getUnits();
580:
581: Iterator<Unit> it = units.iterator();
582: while (it.hasNext()) {
583: Unit stmt = (it.next());
584: InvokeExpr iexpr = null;
585:
586: String errorSuffix = " at " + stmt + " in " + getMethod();
587:
588: if (stmt instanceof DefinitionStmt) {
589: DefinitionStmt astmt = (DefinitionStmt) stmt;
590: if (!(astmt.getRightOp() instanceof CaughtExceptionRef)) {
591: Type leftType = Type.toMachineType(astmt
592: .getLeftOp().getType());
593: Type rightType = Type.toMachineType(astmt
594: .getRightOp().getType());
595:
596: checkCopy(leftType, rightType, errorSuffix);
597: if (astmt.getRightOp() instanceof InvokeExpr)
598: iexpr = (InvokeExpr) (astmt.getRightOp());
599: }
600: }
601:
602: if (stmt instanceof InvokeStmt)
603: iexpr = ((InvokeStmt) stmt).getInvokeExpr();
604:
605: if (iexpr != null) {
606: SootMethodRef called = iexpr.getMethodRef();
607:
608: if (iexpr instanceof InstanceInvokeExpr) {
609: InstanceInvokeExpr iiexpr = (InstanceInvokeExpr) iexpr;
610: checkCopy(called.declaringClass().getType(), iiexpr
611: .getBase().getType(),
612: " in receiver of call" + errorSuffix);
613: }
614:
615: if (called.parameterTypes().size() != iexpr
616: .getArgCount())
617: throw new RuntimeException(
618: "Warning: Argument count doesn't match up with signature in call"
619: + errorSuffix + " in "
620: + getMethod());
621: else
622: for (int i = 0; i < iexpr.getArgCount(); i++)
623: checkCopy(Type.toMachineType(called
624: .parameterType(i)), Type
625: .toMachineType(iexpr.getArg(i)
626: .getType()), " in argument "
627: + i + " of call" + errorSuffix);
628: }
629: }
630: }
631:
632: private void checkCopy(Type leftType, Type rightType,
633: String errorSuffix) {
634: if (leftType instanceof PrimType
635: || rightType instanceof PrimType) {
636: if (leftType instanceof IntType
637: && rightType instanceof IntType)
638: return;
639: if (leftType instanceof LongType
640: && rightType instanceof LongType)
641: return;
642: if (leftType instanceof FloatType
643: && rightType instanceof FloatType)
644: return;
645: if (leftType instanceof DoubleType
646: && rightType instanceof DoubleType)
647: return;
648: throw new RuntimeException(
649: "Warning: Bad use of primitive type" + errorSuffix
650: + " in " + getMethod());
651: }
652:
653: if (rightType instanceof NullType)
654: return;
655: if (leftType instanceof RefType
656: && ((RefType) leftType).getClassName().equals(
657: "java.lang.Object"))
658: return;
659:
660: if (leftType instanceof ArrayType
661: || rightType instanceof ArrayType) {
662: if (leftType instanceof ArrayType
663: && rightType instanceof ArrayType)
664: return;
665:
666: throw new RuntimeException("Warning: Bad use of array type"
667: + errorSuffix + " in " + getMethod());
668: }
669:
670: if (leftType instanceof RefType && rightType instanceof RefType) {
671: SootClass leftClass = ((RefType) leftType).getSootClass();
672: SootClass rightClass = ((RefType) rightType).getSootClass();
673:
674: if (leftClass.isInterface()) {
675: if (rightClass.isInterface()) {
676: if (!(leftClass.getName().equals(
677: rightClass.getName()) || Scene.v()
678: .getActiveHierarchy()
679: .isInterfaceSubinterfaceOf(rightClass,
680: leftClass)))
681: throw new RuntimeException(
682: "Warning: Bad use of interface type"
683: + errorSuffix + " in "
684: + getMethod());
685: } else {
686: // No quick way to check this for now.
687: }
688: } else {
689: if (rightClass.isInterface()) {
690: throw new RuntimeException(
691: "Warning: trying to use interface type where non-Object class expected"
692: + errorSuffix + " in "
693: + getMethod());
694: } else {
695: if (!Scene.v().getActiveHierarchy()
696: .isClassSubclassOfIncluding(rightClass,
697: leftClass))
698: throw new RuntimeException(
699: "Warning: Bad use of class type"
700: + errorSuffix + " in "
701: + getMethod());
702: }
703: }
704: return;
705: }
706: throw new RuntimeException("Warning: Bad types" + errorSuffix
707: + " in " + getMethod());
708: }
709:
710: @SuppressWarnings("unchecked")
711: public void checkInit() {
712: Chain<Unit> units = getUnits();
713: ExceptionalUnitGraph g = new ExceptionalUnitGraph(this ,
714: PedanticThrowAnalysis.v(), false);
715:
716: // FIXME: Work around for bug in soot
717: Scene.v().releaseActiveHierarchy();
718:
719: InitAnalysis analysis = new InitAnalysis(g);
720: Iterator<Unit> it = units.iterator();
721: while (it.hasNext()) {
722: Unit s = (it.next());
723: FlowSet init = (FlowSet) analysis.getFlowBefore(s);
724: List<ValueBox> uses = s.getUseBoxes();
725: Iterator<ValueBox> usesIt = uses.iterator();
726: while (usesIt.hasNext()) {
727: Value v = ((usesIt.next())).getValue();
728: if (v instanceof Local) {
729: Local l = (Local) v;
730: if (!init.contains(l))
731: throw new RuntimeException(
732: "Warning: Local variable " + l
733: + " not definitely defined at "
734: + s + " in " + method);
735: }
736: }
737: }
738: }
739:
740: /**
741: * {@inheritDoc}
742: */
743: @Override
744: public String toString() {
745: ByteArrayOutputStream streamOut = new ByteArrayOutputStream();
746: PrintWriter writerOut = new PrintWriter(new EscapedWriter(
747: new OutputStreamWriter(streamOut)));
748: try {
749: Printer.v().printTo(this , writerOut);
750: } catch (RuntimeException e) {
751: e.printStackTrace(writerOut);
752: }
753: writerOut.flush();
754: writerOut.close();
755: return streamOut.toString();
756: }
757: }
|