more changes.
[IRC.git] / Robust / src / Analysis / SSJava / LocationInference.java
1 package Analysis.SSJava;
2
3 import java.io.IOException;
4 import java.util.ArrayList;
5 import java.util.Collections;
6 import java.util.Comparator;
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.Iterator;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Set;
13
14 import IR.ClassDescriptor;
15 import IR.Descriptor;
16 import IR.FieldDescriptor;
17 import IR.MethodDescriptor;
18 import IR.NameDescriptor;
19 import IR.Operation;
20 import IR.State;
21 import IR.SymbolTable;
22 import IR.TypeDescriptor;
23 import IR.VarDescriptor;
24 import IR.Tree.ArrayAccessNode;
25 import IR.Tree.AssignmentNode;
26 import IR.Tree.BlockExpressionNode;
27 import IR.Tree.BlockNode;
28 import IR.Tree.BlockStatementNode;
29 import IR.Tree.CastNode;
30 import IR.Tree.CreateObjectNode;
31 import IR.Tree.DeclarationNode;
32 import IR.Tree.ExpressionNode;
33 import IR.Tree.FieldAccessNode;
34 import IR.Tree.IfStatementNode;
35 import IR.Tree.Kind;
36 import IR.Tree.LiteralNode;
37 import IR.Tree.LoopNode;
38 import IR.Tree.MethodInvokeNode;
39 import IR.Tree.NameNode;
40 import IR.Tree.OpNode;
41 import IR.Tree.ReturnNode;
42 import IR.Tree.SubBlockNode;
43 import IR.Tree.SwitchStatementNode;
44 import IR.Tree.TertiaryNode;
45
46 public class LocationInference {
47
48   State state;
49   SSJavaAnalysis ssjava;
50
51   List<ClassDescriptor> toanalyzeList;
52   List<MethodDescriptor> toanalyzeMethodList;
53   Map<MethodDescriptor, FlowGraph> mapMethodDescriptorToFlowGraph;
54
55   boolean debug = true;
56
57   public LocationInference(SSJavaAnalysis ssjava, State state) {
58     this.ssjava = ssjava;
59     this.state = state;
60     this.toanalyzeList = new ArrayList<ClassDescriptor>();
61     this.toanalyzeMethodList = new ArrayList<MethodDescriptor>();
62     this.mapMethodDescriptorToFlowGraph = new HashMap<MethodDescriptor, FlowGraph>();
63   }
64
65   public void setupToAnalyze() {
66     SymbolTable classtable = state.getClassSymbolTable();
67     toanalyzeList.clear();
68     toanalyzeList.addAll(classtable.getValueSet());
69     Collections.sort(toanalyzeList, new Comparator<ClassDescriptor>() {
70       public int compare(ClassDescriptor o1, ClassDescriptor o2) {
71         return o1.getClassName().compareToIgnoreCase(o2.getClassName());
72       }
73     });
74   }
75
76   public void setupToAnalazeMethod(ClassDescriptor cd) {
77
78     SymbolTable methodtable = cd.getMethodTable();
79     toanalyzeMethodList.clear();
80     toanalyzeMethodList.addAll(methodtable.getValueSet());
81     Collections.sort(toanalyzeMethodList, new Comparator<MethodDescriptor>() {
82       public int compare(MethodDescriptor o1, MethodDescriptor o2) {
83         return o1.getSymbol().compareToIgnoreCase(o2.getSymbol());
84       }
85     });
86   }
87
88   public boolean toAnalyzeMethodIsEmpty() {
89     return toanalyzeMethodList.isEmpty();
90   }
91
92   public boolean toAnalyzeIsEmpty() {
93     return toanalyzeList.isEmpty();
94   }
95
96   public ClassDescriptor toAnalyzeNext() {
97     return toanalyzeList.remove(0);
98   }
99
100   public MethodDescriptor toAnalyzeMethodNext() {
101     return toanalyzeMethodList.remove(0);
102   }
103
104   public void inference() {
105
106     // 2) construct value flow graph
107
108     setupToAnalyze();
109
110     while (!toAnalyzeIsEmpty()) {
111       ClassDescriptor cd = toAnalyzeNext();
112
113       setupToAnalazeMethod(cd);
114       while (!toAnalyzeMethodIsEmpty()) {
115         MethodDescriptor md = toAnalyzeMethodNext();
116         if (ssjava.needTobeAnnotated(md)) {
117           if (state.SSJAVADEBUG) {
118             System.out.println("SSJAVA: Constructing a flow graph: " + md);
119           }
120           FlowGraph fg = new FlowGraph(md);
121           mapMethodDescriptorToFlowGraph.put(md, fg);
122           analyzeMethodBody(cd, md);
123         }
124       }
125     }
126
127     _debug_printGraph();
128
129   }
130
131   private void analyzeMethodBody(ClassDescriptor cd, MethodDescriptor md) {
132     BlockNode bn = state.getMethodBody(md);
133     analyzeFlowBlockNode(md, md.getParameterTable(), bn, null);
134   }
135
136   private void analyzeFlowBlockNode(MethodDescriptor md, SymbolTable nametable, BlockNode bn,
137       NodeTupleSet implicitFlowTupleSet) {
138
139     bn.getVarTable().setParent(nametable);
140     for (int i = 0; i < bn.size(); i++) {
141       BlockStatementNode bsn = bn.get(i);
142       analyzeBlockStatementNode(md, bn.getVarTable(), bsn, implicitFlowTupleSet);
143     }
144
145   }
146
147   private void analyzeBlockStatementNode(MethodDescriptor md, SymbolTable nametable,
148       BlockStatementNode bsn, NodeTupleSet implicitFlowTupleSet) {
149
150     switch (bsn.kind()) {
151     case Kind.BlockExpressionNode:
152       analyzeBlockExpressionNode(md, nametable, (BlockExpressionNode) bsn, implicitFlowTupleSet);
153       break;
154
155     case Kind.DeclarationNode:
156       analyzeFlowDeclarationNode(md, nametable, (DeclarationNode) bsn, implicitFlowTupleSet);
157       break;
158
159     case Kind.IfStatementNode:
160       analyzeFlowIfStatementNode(md, nametable, (IfStatementNode) bsn, implicitFlowTupleSet);
161       break;
162
163     case Kind.LoopNode:
164       analyzeFlowLoopNode(md, nametable, (LoopNode) bsn, implicitFlowTupleSet);
165       break;
166
167     case Kind.ReturnNode:
168       analyzeReturnNode(md, nametable, (ReturnNode) bsn);
169       break;
170
171     case Kind.SubBlockNode:
172       analyzeFlowSubBlockNode(md, nametable, (SubBlockNode) bsn, implicitFlowTupleSet);
173       break;
174
175     case Kind.ContinueBreakNode:
176       break;
177
178     case Kind.SwitchStatementNode:
179       analyzeSwitchStatementNode(md, nametable, (SwitchStatementNode) bsn);
180       break;
181
182     }
183
184   }
185
186   private void analyzeSwitchStatementNode(MethodDescriptor md, SymbolTable nametable,
187       SwitchStatementNode bsn) {
188     // TODO Auto-generated method stub
189
190   }
191
192   private void analyzeFlowSubBlockNode(MethodDescriptor md, SymbolTable nametable,
193       SubBlockNode sbn, NodeTupleSet implicitFlowTupleSet) {
194     analyzeFlowBlockNode(md, nametable, sbn.getBlockNode(), implicitFlowTupleSet);
195   }
196
197   private void analyzeReturnNode(MethodDescriptor md, SymbolTable nametable, ReturnNode bsn) {
198     // TODO Auto-generated method stub
199
200   }
201
202   private void analyzeFlowLoopNode(MethodDescriptor md, SymbolTable nametable, LoopNode ln,
203       NodeTupleSet implicitFlowTupleSet) {
204
205     if (ln.getType() == LoopNode.WHILELOOP || ln.getType() == LoopNode.DOWHILELOOP) {
206
207       NodeTupleSet condTupleNode = new NodeTupleSet();
208       analyzeFlowExpressionNode(md, nametable, ln.getCondition(), condTupleNode, null,
209           implicitFlowTupleSet);
210       condTupleNode.addTupleSet(implicitFlowTupleSet);
211       System.out.println("condTupleNode=" + condTupleNode);
212
213       // add edges from condNodeTupleSet to all nodes of conditional nodes
214       analyzeFlowBlockNode(md, nametable, ln.getBody(), condTupleNode);
215
216     } else {
217       // check 'for loop' case
218       BlockNode bn = ln.getInitializer();
219       analyzeFlowBlockNode(md, nametable, bn, implicitFlowTupleSet);
220       bn.getVarTable().setParent(nametable);
221
222       NodeTupleSet condTupleNode = new NodeTupleSet();
223       analyzeFlowExpressionNode(md, nametable, ln.getCondition(), condTupleNode, null,
224           implicitFlowTupleSet);
225       condTupleNode.addTupleSet(implicitFlowTupleSet);
226       System.out.println("condTupleNode=" + condTupleNode);
227
228       analyzeFlowBlockNode(md, bn.getVarTable(), ln.getUpdate(), condTupleNode);
229       analyzeFlowBlockNode(md, bn.getVarTable(), ln.getBody(), condTupleNode);
230
231     }
232
233   }
234
235   private void analyzeFlowIfStatementNode(MethodDescriptor md, SymbolTable nametable,
236       IfStatementNode isn, NodeTupleSet implicitFlowTupleSet) {
237
238     NodeTupleSet condTupleNode = new NodeTupleSet();
239     analyzeFlowExpressionNode(md, nametable, isn.getCondition(), condTupleNode, null,
240         implicitFlowTupleSet);
241
242     // add edges from condNodeTupleSet to all nodes of conditional nodes
243     condTupleNode.addTupleSet(implicitFlowTupleSet);
244     analyzeFlowBlockNode(md, nametable, isn.getTrueBlock(), condTupleNode);
245
246     if (isn.getFalseBlock() != null) {
247       analyzeFlowBlockNode(md, nametable, isn.getFalseBlock(), condTupleNode);
248     }
249
250   }
251
252   private void analyzeFlowDeclarationNode(MethodDescriptor md, SymbolTable nametable,
253       DeclarationNode dn, NodeTupleSet implicitFlowTupleSet) {
254
255     VarDescriptor vd = dn.getVarDescriptor();
256     NTuple<Descriptor> tupleLHS = new NTuple<Descriptor>();
257     tupleLHS.add(vd);
258     getFlowGraph(md).createNewFlowNode(tupleLHS);
259
260     if (dn.getExpression() != null) {
261
262       NodeTupleSet tupleSetRHS = new NodeTupleSet();
263       analyzeFlowExpressionNode(md, nametable, dn.getExpression(), tupleSetRHS, null,
264           implicitFlowTupleSet);
265
266       // add a new flow edge from rhs to lhs
267       for (Iterator<NTuple<Descriptor>> iter = tupleSetRHS.iterator(); iter.hasNext();) {
268         NTuple<Descriptor> from = iter.next();
269         addFlowGraphEdge(md, from, tupleLHS);
270       }
271
272     }
273
274   }
275
276   private void analyzeBlockExpressionNode(MethodDescriptor md, SymbolTable nametable,
277       BlockExpressionNode ben, NodeTupleSet implicitFlowTupleSet) {
278     analyzeFlowExpressionNode(md, nametable, ben.getExpression(), null, null, implicitFlowTupleSet);
279   }
280
281   private NTuple<Descriptor> analyzeFlowExpressionNode(MethodDescriptor md, SymbolTable nametable,
282       ExpressionNode en, NodeTupleSet nodeSet, NTuple<Descriptor> base,
283       NodeTupleSet implicitFlowTupleSet) {
284
285     // note that expression node can create more than one flow node
286     // nodeSet contains of flow nodes
287     // base is always assigned to null except name node case!
288
289     NTuple<Descriptor> flowTuple;
290
291     switch (en.kind()) {
292
293     case Kind.AssignmentNode:
294       analyzeFlowAssignmentNode(md, nametable, (AssignmentNode) en, base, implicitFlowTupleSet);
295       break;
296
297     case Kind.FieldAccessNode:
298       flowTuple =
299           analyzeFlowFieldAccessNode(md, nametable, (FieldAccessNode) en, nodeSet, base,
300               implicitFlowTupleSet);
301       nodeSet.addTuple(flowTuple);
302       return flowTuple;
303
304     case Kind.NameNode:
305       NodeTupleSet nameNodeSet = new NodeTupleSet();
306       flowTuple =
307           analyzeFlowNameNode(md, nametable, (NameNode) en, nameNodeSet, base, implicitFlowTupleSet);
308       nodeSet.addTuple(flowTuple);
309       return flowTuple;
310
311     case Kind.OpNode:
312       analyzeFlowOpNode(md, nametable, (OpNode) en, nodeSet, implicitFlowTupleSet);
313       break;
314
315     case Kind.CreateObjectNode:
316       analyzeCreateObjectNode(md, nametable, (CreateObjectNode) en);
317       break;
318
319     case Kind.ArrayAccessNode:
320       analyzeArrayAccessNode(md, nametable, (ArrayAccessNode) en);
321       break;
322
323     case Kind.LiteralNode:
324       analyzeLiteralNode(md, nametable, (LiteralNode) en);
325       break;
326
327     case Kind.MethodInvokeNode:
328       analyzeMethodInvokeNode(md, nametable, (MethodInvokeNode) en);
329       break;
330
331     case Kind.TertiaryNode:
332       analyzeTertiaryNode(md, nametable, (TertiaryNode) en);
333       break;
334
335     case Kind.CastNode:
336       analyzeCastNode(md, nametable, (CastNode) en);
337       break;
338
339     // case Kind.InstanceOfNode:
340     // checkInstanceOfNode(md, nametable, (InstanceOfNode) en, td);
341     // return null;
342
343     // case Kind.ArrayInitializerNode:
344     // checkArrayInitializerNode(md, nametable, (ArrayInitializerNode) en,
345     // td);
346     // return null;
347
348     // case Kind.ClassTypeNode:
349     // checkClassTypeNode(md, nametable, (ClassTypeNode) en, td);
350     // return null;
351
352     // case Kind.OffsetNode:
353     // checkOffsetNode(md, nametable, (OffsetNode)en, td);
354     // return null;
355
356     }
357     return null;
358
359   }
360
361   private void analyzeCastNode(MethodDescriptor md, SymbolTable nametable, CastNode en) {
362     // TODO Auto-generated method stub
363
364   }
365
366   private void analyzeTertiaryNode(MethodDescriptor md, SymbolTable nametable, TertiaryNode en) {
367     // TODO Auto-generated method stub
368
369   }
370
371   private void analyzeMethodInvokeNode(MethodDescriptor md, SymbolTable nametable,
372       MethodInvokeNode en) {
373     // TODO Auto-generated method stub
374
375   }
376
377   private void analyzeLiteralNode(MethodDescriptor md, SymbolTable nametable, LiteralNode en) {
378     // TODO Auto-generated method stub
379
380   }
381
382   private void analyzeArrayAccessNode(MethodDescriptor md, SymbolTable nametable, ArrayAccessNode en) {
383     // TODO Auto-generated method stub
384
385   }
386
387   private void analyzeCreateObjectNode(MethodDescriptor md, SymbolTable nametable,
388       CreateObjectNode en) {
389     // TODO Auto-generated method stub
390
391   }
392
393   private void analyzeFlowOpNode(MethodDescriptor md, SymbolTable nametable, OpNode on,
394       NodeTupleSet nodeSet, NodeTupleSet implicitFlowTupleSet) {
395
396     NodeTupleSet leftOpSet = new NodeTupleSet();
397     NodeTupleSet rightOpSet = new NodeTupleSet();
398
399     // left operand
400     analyzeFlowExpressionNode(md, nametable, on.getLeft(), leftOpSet, null, implicitFlowTupleSet);
401     System.out.println("leftOpSet=" + leftOpSet);
402
403     if (on.getRight() != null) {
404       // right operand
405       analyzeFlowExpressionNode(md, nametable, on.getRight(), rightOpSet, null,
406           implicitFlowTupleSet);
407       System.out.println("rightOpSet=" + rightOpSet);
408     }
409
410     Operation op = on.getOp();
411
412     switch (op.getOp()) {
413
414     case Operation.UNARYPLUS:
415     case Operation.UNARYMINUS:
416     case Operation.LOGIC_NOT:
417       // single operand
418       nodeSet.addTupleSet(leftOpSet);
419       break;
420
421     case Operation.LOGIC_OR:
422     case Operation.LOGIC_AND:
423     case Operation.COMP:
424     case Operation.BIT_OR:
425     case Operation.BIT_XOR:
426     case Operation.BIT_AND:
427     case Operation.ISAVAILABLE:
428     case Operation.EQUAL:
429     case Operation.NOTEQUAL:
430     case Operation.LT:
431     case Operation.GT:
432     case Operation.LTE:
433     case Operation.GTE:
434     case Operation.ADD:
435     case Operation.SUB:
436     case Operation.MULT:
437     case Operation.DIV:
438     case Operation.MOD:
439     case Operation.LEFTSHIFT:
440     case Operation.RIGHTSHIFT:
441     case Operation.URIGHTSHIFT:
442
443       // there are two operands
444       nodeSet.addTupleSet(leftOpSet);
445       nodeSet.addTupleSet(rightOpSet);
446       break;
447
448     default:
449       throw new Error(op.toString());
450     }
451   }
452
453   private NTuple<Descriptor> analyzeFlowNameNode(MethodDescriptor md, SymbolTable nametable,
454       NameNode nn, NodeTupleSet nodeSet, NTuple<Descriptor> base, NodeTupleSet implicitFlowTupleSet) {
455
456     if (base == null) {
457       base = new NTuple<Descriptor>();
458     }
459
460     NameDescriptor nd = nn.getName();
461     if (nd.getBase() != null) {
462       analyzeFlowExpressionNode(md, nametable, nn.getExpression(), nodeSet, base,
463           implicitFlowTupleSet);
464     } else {
465       String varname = nd.toString();
466       if (varname.equals("this")) {
467         // 'this' itself!
468         base.add(md.getThis());
469         return base;
470       }
471
472       Descriptor d = (Descriptor) nametable.get(varname);
473
474       // CompositeLocation localLoc = null;
475       if (d instanceof VarDescriptor) {
476         VarDescriptor vd = (VarDescriptor) d;
477         // localLoc = d2loc.get(vd);
478         // the type of var descriptor has a composite location!
479         // loc = ((SSJavaType)
480         // vd.getType().getExtension()).getCompLoc().clone();
481         base.add(vd);
482       } else if (d instanceof FieldDescriptor) {
483         // the type of field descriptor has a location!
484         FieldDescriptor fd = (FieldDescriptor) d;
485         if (fd.isStatic()) {
486           if (fd.isFinal()) {
487             // if it is 'static final', the location has TOP since no one can
488             // change its value
489             // loc.addLocation(Location.createTopLocation(md));
490             // return loc;
491           } else {
492             // if 'static', the location has pre-assigned global loc
493             // MethodLattice<String> localLattice = ssjava.getMethodLattice(md);
494             // String globalLocId = localLattice.getGlobalLoc();
495             // if (globalLocId == null) {
496             // throw new
497             // Error("Global location element is not defined in the method " +
498             // md);
499             // }
500             // Location globalLoc = new Location(md, globalLocId);
501             //
502             // loc.addLocation(globalLoc);
503           }
504         } else {
505           // the location of field access starts from this, followed by field
506           // location
507           base.add(md.getThis());
508         }
509
510         base.add(fd);
511       } else if (d == null) {
512         // access static field
513         // FieldDescriptor fd = nn.getField();addFlowGraphEdge
514         //
515         // MethodLattice<String> localLattice = ssjava.getMethodLattice(md);
516         // String globalLocId = localLattice.getGlobalLoc();
517         // if (globalLocId == null) {
518         // throw new
519         // Error("Method lattice does not define global variable location at "
520         // + generateErrorMessage(md.getClassDesc(), nn));
521         // }
522         // loc.addLocation(new Location(md, globalLocId));
523         //
524         // Location fieldLoc = (Location) fd.getType().getExtension();
525         // loc.addLocation(fieldLoc);
526         //
527         // return loc;
528
529       }
530     }
531
532     getFlowGraph(md).createNewFlowNode(base);
533
534     return base;
535
536   }
537
538   private NTuple<Descriptor> analyzeFlowFieldAccessNode(MethodDescriptor md, SymbolTable nametable,
539       FieldAccessNode fan, NodeTupleSet nodeSet, NTuple<Descriptor> base,
540       NodeTupleSet implicitFlowTupleSet) {
541
542     ExpressionNode left = fan.getExpression();
543     TypeDescriptor ltd = left.getType();
544     FieldDescriptor fd = fan.getField();
545
546     String varName = null;
547     if (left.kind() == Kind.NameNode) {
548       NameDescriptor nd = ((NameNode) left).getName();
549       varName = nd.toString();
550     }
551
552     if (ltd.isClassNameRef() || (varName != null && varName.equals("this"))) {
553       // using a class name directly or access using this
554       if (fd.isStatic() && fd.isFinal()) {
555         // loc.addLocation(Location.createTopLocation(md));
556         // return loc;
557       }
558     }
559
560     // if (left instanceof ArrayAccessNode) {
561     // ArrayAccessNode aan = (ArrayAccessNode) left;
562     // left = aan.getExpression();
563     // }
564     // fanNodeSet
565     base = analyzeFlowExpressionNode(md, nametable, left, nodeSet, base, implicitFlowTupleSet);
566
567     if (!left.getType().isPrimitive()) {
568
569       if (fd.getSymbol().equals("length")) {
570         // TODO
571         // array.length access, return the location of the array
572         // return loc;
573       }
574
575       base.add(fd);
576     }
577
578     return base;
579
580   }
581
582   private void analyzeFlowAssignmentNode(MethodDescriptor md, SymbolTable nametable,
583       AssignmentNode an, NTuple<Descriptor> base, NodeTupleSet implicitFlowTupleSet) {
584
585     System.out.println("analyzeFlowAssignmentNode=" + an);
586
587     NodeTupleSet nodeSetRHS = new NodeTupleSet();
588     NodeTupleSet nodeSetLHS = new NodeTupleSet();
589
590     boolean postinc = true;
591     if (an.getOperation().getBaseOp() == null
592         || (an.getOperation().getBaseOp().getOp() != Operation.POSTINC && an.getOperation()
593             .getBaseOp().getOp() != Operation.POSTDEC)) {
594       postinc = false;
595     }
596
597     // if LHS is array access node, need to capture value flows between an array
598     // and its index value
599     analyzeFlowExpressionNode(md, nametable, an.getDest(), nodeSetLHS, null, implicitFlowTupleSet);
600     System.out.println("ASSIGNMENT NODE nodeSetLHS=" + nodeSetLHS);
601     // NTuple<Descriptor> lhsDescTuple = analyzeFlowExpressionNode(md,
602     // nametable, an.getDest(), base);
603
604     if (!postinc) {
605       // analyze value flows of rhs expression
606       analyzeFlowExpressionNode(md, nametable, an.getSrc(), nodeSetRHS, null, implicitFlowTupleSet);
607       System.out.println("ASSIGNMENT NODE nodeSetRHS=" + nodeSetRHS);
608
609       // creates edges from RHS to LHS
610       for (Iterator<NTuple<Descriptor>> iter = nodeSetRHS.iterator(); iter.hasNext();) {
611         NTuple<Descriptor> fromTuple = iter.next();
612         for (Iterator<NTuple<Descriptor>> iter2 = nodeSetLHS.iterator(); iter2.hasNext();) {
613           NTuple<Descriptor> toTuple = iter2.next();
614           addFlowGraphEdge(md, fromTuple, toTuple);
615         }
616       }
617
618       // creates edges from implicitFlowTupleSet to LHS
619       for (Iterator<NTuple<Descriptor>> iter = implicitFlowTupleSet.iterator(); iter.hasNext();) {
620         NTuple<Descriptor> fromTuple = iter.next();
621         for (Iterator<NTuple<Descriptor>> iter2 = nodeSetLHS.iterator(); iter2.hasNext();) {
622           NTuple<Descriptor> toTuple = iter2.next();
623           addFlowGraphEdge(md, fromTuple, toTuple);
624         }
625       }
626
627     } else {
628       // postinc case
629       for (Iterator<NTuple<Descriptor>> iter2 = nodeSetLHS.iterator(); iter2.hasNext();) {
630         NTuple<Descriptor> tuple = iter2.next();
631         addFlowGraphEdge(md, tuple, tuple);
632       }
633
634     }
635
636   }
637
638   public FlowGraph getFlowGraph(MethodDescriptor md) {
639     return mapMethodDescriptorToFlowGraph.get(md);
640   }
641
642   public void addFlowGraphEdge(MethodDescriptor md, NTuple<Descriptor> from, NTuple<Descriptor> to) {
643     FlowGraph graph = getFlowGraph(md);
644     graph.addValueFlowEdge(from, to);
645   }
646
647   public void _debug_printGraph() {
648     Set<MethodDescriptor> keySet = mapMethodDescriptorToFlowGraph.keySet();
649
650     for (Iterator<MethodDescriptor> iterator = keySet.iterator(); iterator.hasNext();) {
651       MethodDescriptor md = (MethodDescriptor) iterator.next();
652       FlowGraph fg = mapMethodDescriptorToFlowGraph.get(md);
653       try {
654         fg.writeGraph();
655       } catch (IOException e) {
656         e.printStackTrace();
657       }
658     }
659
660   }
661
662 }