219dffe281e6679d056188321516296313227ac0
[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.Collection;
6 import java.util.Collections;
7 import java.util.Comparator;
8 import java.util.HashMap;
9 import java.util.HashSet;
10 import java.util.Iterator;
11 import java.util.LinkedList;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Set;
15 import java.util.Stack;
16
17 import IR.ClassDescriptor;
18 import IR.Descriptor;
19 import IR.FieldDescriptor;
20 import IR.MethodDescriptor;
21 import IR.NameDescriptor;
22 import IR.Operation;
23 import IR.State;
24 import IR.SymbolTable;
25 import IR.TypeDescriptor;
26 import IR.VarDescriptor;
27 import IR.Tree.ArrayAccessNode;
28 import IR.Tree.AssignmentNode;
29 import IR.Tree.BlockExpressionNode;
30 import IR.Tree.BlockNode;
31 import IR.Tree.BlockStatementNode;
32 import IR.Tree.CastNode;
33 import IR.Tree.CreateObjectNode;
34 import IR.Tree.DeclarationNode;
35 import IR.Tree.ExpressionNode;
36 import IR.Tree.FieldAccessNode;
37 import IR.Tree.IfStatementNode;
38 import IR.Tree.Kind;
39 import IR.Tree.LiteralNode;
40 import IR.Tree.LoopNode;
41 import IR.Tree.MethodInvokeNode;
42 import IR.Tree.NameNode;
43 import IR.Tree.OpNode;
44 import IR.Tree.ReturnNode;
45 import IR.Tree.SubBlockNode;
46 import IR.Tree.SwitchStatementNode;
47 import IR.Tree.TertiaryNode;
48 import IR.Tree.TreeNode;
49
50 public class LocationInference {
51
52   State state;
53   SSJavaAnalysis ssjava;
54
55   List<ClassDescriptor> toanalyzeList;
56   List<MethodDescriptor> toanalyzeMethodList;
57   Map<MethodDescriptor, FlowGraph> mapMethodDescriptorToFlowGraph;
58
59   // map a method descriptor to its set of parameter descriptors
60   Map<MethodDescriptor, Set<Descriptor>> mapMethodDescriptorToParamDescSet;
61
62   // keep current descriptors to visit in fixed-point interprocedural analysis,
63   private Stack<MethodDescriptor> methodDescriptorsToVisitStack;
64
65   // map a class descriptor to a field lattice
66   private Map<ClassDescriptor, SSJavaLattice<String>> cd2lattice;
67
68   // map a method descriptor to a method lattice
69   private Map<MethodDescriptor, SSJavaLattice<String>> md2lattice;
70
71   // map a method descriptor to the set of method invocation nodes which are
72   // invoked by the method descriptor
73   private Map<MethodDescriptor, Set<MethodInvokeNode>> mapMethodDescriptorToMethodInvokeNodeSet;
74
75   private Map<MethodInvokeNode, Map<Integer, NTuple<Descriptor>>> mapMethodInvokeNodeToArgIdxMap;
76
77   private Map<MethodDescriptor, MethodLocationInfo> mapMethodDescToMethodLocationInfo;
78
79   private Map<ClassDescriptor, LocationInfo> mapClassToLocationInfo;
80
81   private Map<MethodDescriptor, Set<MethodDescriptor>> mapMethodToCalleeSet;
82
83   public static final String GLOBALLOC = "GLOBALLOC";
84
85   public static final String TOPLOC = "TOPLOC";
86
87   public static final Descriptor GLOBALDESC = new NameDescriptor(GLOBALLOC);
88
89   public static final Descriptor TOPDESC = new NameDescriptor(TOPLOC);
90
91   boolean debug = true;
92
93   public LocationInference(SSJavaAnalysis ssjava, State state) {
94     this.ssjava = ssjava;
95     this.state = state;
96     this.toanalyzeList = new ArrayList<ClassDescriptor>();
97     this.toanalyzeMethodList = new ArrayList<MethodDescriptor>();
98     this.mapMethodDescriptorToFlowGraph = new HashMap<MethodDescriptor, FlowGraph>();
99     this.cd2lattice = new HashMap<ClassDescriptor, SSJavaLattice<String>>();
100     this.md2lattice = new HashMap<MethodDescriptor, SSJavaLattice<String>>();
101     this.methodDescriptorsToVisitStack = new Stack<MethodDescriptor>();
102     this.mapMethodDescriptorToMethodInvokeNodeSet =
103         new HashMap<MethodDescriptor, Set<MethodInvokeNode>>();
104     this.mapMethodInvokeNodeToArgIdxMap =
105         new HashMap<MethodInvokeNode, Map<Integer, NTuple<Descriptor>>>();
106     this.mapMethodDescToMethodLocationInfo = new HashMap<MethodDescriptor, MethodLocationInfo>();
107     this.mapMethodToCalleeSet = new HashMap<MethodDescriptor, Set<MethodDescriptor>>();
108     this.mapClassToLocationInfo = new HashMap<ClassDescriptor, LocationInfo>();
109   }
110
111   public void setupToAnalyze() {
112     SymbolTable classtable = state.getClassSymbolTable();
113     toanalyzeList.clear();
114     toanalyzeList.addAll(classtable.getValueSet());
115     Collections.sort(toanalyzeList, new Comparator<ClassDescriptor>() {
116       public int compare(ClassDescriptor o1, ClassDescriptor o2) {
117         return o1.getClassName().compareToIgnoreCase(o2.getClassName());
118       }
119     });
120   }
121
122   public void setupToAnalazeMethod(ClassDescriptor cd) {
123
124     SymbolTable methodtable = cd.getMethodTable();
125     toanalyzeMethodList.clear();
126     toanalyzeMethodList.addAll(methodtable.getValueSet());
127     Collections.sort(toanalyzeMethodList, new Comparator<MethodDescriptor>() {
128       public int compare(MethodDescriptor o1, MethodDescriptor o2) {
129         return o1.getSymbol().compareToIgnoreCase(o2.getSymbol());
130       }
131     });
132   }
133
134   public boolean toAnalyzeMethodIsEmpty() {
135     return toanalyzeMethodList.isEmpty();
136   }
137
138   public boolean toAnalyzeIsEmpty() {
139     return toanalyzeList.isEmpty();
140   }
141
142   public ClassDescriptor toAnalyzeNext() {
143     return toanalyzeList.remove(0);
144   }
145
146   public MethodDescriptor toAnalyzeMethodNext() {
147     return toanalyzeMethodList.remove(0);
148   }
149
150   public void inference() {
151
152     // 1) construct value flow graph
153     constructFlowGraph();
154
155     // 2) construct lattices
156     inferLattices();
157
158     simplifyLattices();
159
160     debug_writeLatticeDotFile();
161
162     // 3) check properties
163     checkLattices();
164
165   }
166
167   private void simplifyLattices() {
168
169     // generate lattice dot file
170     setupToAnalyze();
171
172     while (!toAnalyzeIsEmpty()) {
173       ClassDescriptor cd = toAnalyzeNext();
174
175       setupToAnalazeMethod(cd);
176
177       SSJavaLattice<String> classLattice = cd2lattice.get(cd);
178       if (classLattice != null) {
179         classLattice.removeRedundantEdges();
180       }
181
182       while (!toAnalyzeMethodIsEmpty()) {
183         MethodDescriptor md = toAnalyzeMethodNext();
184         if (ssjava.needTobeAnnotated(md)) {
185           SSJavaLattice<String> methodLattice = md2lattice.get(md);
186           if (methodLattice != null) {
187             methodLattice.removeRedundantEdges();
188           }
189         }
190       }
191     }
192
193   }
194
195   private void checkLattices() {
196
197     LinkedList<MethodDescriptor> descriptorListToAnalyze = ssjava.getSortedDescriptors();
198
199     // current descriptors to visit in fixed-point interprocedural analysis,
200     // prioritized by
201     // dependency in the call graph
202     methodDescriptorsToVisitStack.clear();
203
204     descriptorListToAnalyze.removeFirst();
205
206     Set<MethodDescriptor> methodDescriptorToVistSet = new HashSet<MethodDescriptor>();
207     methodDescriptorToVistSet.addAll(descriptorListToAnalyze);
208
209     while (!descriptorListToAnalyze.isEmpty()) {
210       MethodDescriptor md = descriptorListToAnalyze.removeFirst();
211       checkLatticesOfVirtualMethods(md);
212     }
213
214   }
215
216   private void debug_writeLatticeDotFile() {
217     // generate lattice dot file
218
219     setupToAnalyze();
220
221     while (!toAnalyzeIsEmpty()) {
222       ClassDescriptor cd = toAnalyzeNext();
223
224       setupToAnalazeMethod(cd);
225
226       SSJavaLattice<String> classLattice = cd2lattice.get(cd);
227       if (classLattice != null) {
228         ssjava.writeLatticeDotFile(cd, null, classLattice);
229         debug_printDescriptorToLocNameMapping(cd);
230       }
231
232       while (!toAnalyzeMethodIsEmpty()) {
233         MethodDescriptor md = toAnalyzeMethodNext();
234         if (ssjava.needTobeAnnotated(md)) {
235           SSJavaLattice<String> methodLattice = md2lattice.get(md);
236           if (methodLattice != null) {
237             ssjava.writeLatticeDotFile(cd, md, methodLattice);
238             debug_printDescriptorToLocNameMapping(md);
239           }
240         }
241       }
242     }
243
244   }
245
246   private void debug_printDescriptorToLocNameMapping(Descriptor desc) {
247
248     LocationInfo info = getLocationInfo(desc);
249     System.out.println("## " + desc + " ##");
250     System.out.println(info.getMapDescToInferLocation());
251     LocationInfo locInfo = getLocationInfo(desc);
252     System.out.println("mapping=" + locInfo.getMapLocSymbolToDescSet());
253     System.out.println("###################");
254
255   }
256
257   private void inferLattices() {
258
259     // do fixed-point analysis
260
261     LinkedList<MethodDescriptor> descriptorListToAnalyze = ssjava.getSortedDescriptors();
262
263     Collections.sort(descriptorListToAnalyze, new Comparator<MethodDescriptor>() {
264       public int compare(MethodDescriptor o1, MethodDescriptor o2) {
265         return o1.getSymbol().compareToIgnoreCase(o2.getSymbol());
266       }
267     });
268
269     // current descriptors to visit in fixed-point interprocedural analysis,
270     // prioritized by
271     // dependency in the call graph
272     methodDescriptorsToVisitStack.clear();
273
274     descriptorListToAnalyze.removeFirst();
275
276     Set<MethodDescriptor> methodDescriptorToVistSet = new HashSet<MethodDescriptor>();
277     methodDescriptorToVistSet.addAll(descriptorListToAnalyze);
278
279     while (!descriptorListToAnalyze.isEmpty()) {
280       MethodDescriptor md = descriptorListToAnalyze.removeFirst();
281       methodDescriptorsToVisitStack.add(md);
282     }
283
284     // analyze scheduled methods until there are no more to visit
285     while (!methodDescriptorsToVisitStack.isEmpty()) {
286       // start to analyze leaf node
287       MethodDescriptor md = methodDescriptorsToVisitStack.pop();
288
289       SSJavaLattice<String> methodLattice =
290           new SSJavaLattice<String>(SSJavaAnalysis.TOP, SSJavaAnalysis.BOTTOM);
291
292       MethodLocationInfo methodInfo = new MethodLocationInfo(md);
293
294       System.out.println();
295       System.out.println("SSJAVA: Inferencing the lattice from " + md);
296
297       analyzeMethodLattice(md, methodLattice, methodInfo);
298
299       SSJavaLattice<String> prevMethodLattice = getMethodLattice(md);
300       MethodLocationInfo prevMethodInfo = getMethodLocationInfo(md);
301
302       if ((!methodLattice.equals(prevMethodLattice)) || (!methodInfo.equals(prevMethodInfo))) {
303
304         setMethodLattice(md, methodLattice);
305         setMethodLocInfo(md, methodInfo);
306
307         // results for callee changed, so enqueue dependents caller for
308         // further analysis
309         Iterator<MethodDescriptor> depsItr = ssjava.getDependents(md).iterator();
310         while (depsItr.hasNext()) {
311           MethodDescriptor methodNext = depsItr.next();
312           if (!methodDescriptorsToVisitStack.contains(methodNext)
313               && methodDescriptorToVistSet.contains(methodNext)) {
314             methodDescriptorsToVisitStack.add(methodNext);
315           }
316         }
317
318       }
319
320     }
321   }
322
323   private void setMethodLocInfo(MethodDescriptor md, MethodLocationInfo methodInfo) {
324     mapMethodDescToMethodLocationInfo.put(md, methodInfo);
325   }
326
327   private void checkLatticesOfVirtualMethods(MethodDescriptor md) {
328
329     if (!md.isStatic()) {
330       Set<MethodDescriptor> setPossibleCallees = new HashSet<MethodDescriptor>();
331       setPossibleCallees.addAll(ssjava.getCallGraph().getMethods(md));
332
333       for (Iterator iterator = setPossibleCallees.iterator(); iterator.hasNext();) {
334         MethodDescriptor mdCallee = (MethodDescriptor) iterator.next();
335         if (!md.equals(mdCallee)) {
336           checkConsistency(md, mdCallee);
337         }
338       }
339
340     }
341
342   }
343
344   private void checkConsistency(MethodDescriptor md1, MethodDescriptor md2) {
345
346     // check that two lattice have the same relations between parameters(+PC
347     // LOC, GLOBAL_LOC RETURN LOC)
348
349     List<CompositeLocation> list1 = new ArrayList<CompositeLocation>();
350     List<CompositeLocation> list2 = new ArrayList<CompositeLocation>();
351
352     MethodLocationInfo locInfo1 = getMethodLocationInfo(md1);
353     MethodLocationInfo locInfo2 = getMethodLocationInfo(md2);
354
355     Map<Integer, CompositeLocation> paramMap1 = locInfo1.getMapParamIdxToInferLoc();
356     Map<Integer, CompositeLocation> paramMap2 = locInfo2.getMapParamIdxToInferLoc();
357
358     int numParam = locInfo1.getMapParamIdxToInferLoc().keySet().size();
359
360     // add location types of paramters
361     for (int idx = 0; idx < numParam; idx++) {
362       list1.add(paramMap1.get(Integer.valueOf(idx)));
363       list2.add(paramMap2.get(Integer.valueOf(idx)));
364     }
365
366     // add program counter location
367     list1.add(locInfo1.getPCLoc());
368     list2.add(locInfo2.getPCLoc());
369
370     if (!md1.getReturnType().isVoid()) {
371       // add return value location
372       CompositeLocation rtrLoc1 =
373           new CompositeLocation(new Location(md1, locInfo1.getReturnLocName()));
374       CompositeLocation rtrLoc2 =
375           new CompositeLocation(new Location(md2, locInfo2.getReturnLocName()));
376       list1.add(rtrLoc1);
377       list2.add(rtrLoc2);
378     }
379
380     // add global location type
381     if (md1.isStatic()) {
382       CompositeLocation globalLoc1 =
383           new CompositeLocation(new Location(md1, locInfo1.getGlobalLocName()));
384       CompositeLocation globalLoc2 =
385           new CompositeLocation(new Location(md2, locInfo2.getGlobalLocName()));
386       list1.add(globalLoc1);
387       list2.add(globalLoc2);
388     }
389
390     for (int i = 0; i < list1.size(); i++) {
391       CompositeLocation locA1 = list1.get(i);
392       CompositeLocation locA2 = list2.get(i);
393       for (int k = 0; k < list1.size(); k++) {
394         if (i != k) {
395           CompositeLocation locB1 = list1.get(k);
396           CompositeLocation locB2 = list2.get(k);
397           boolean r1 = isGreaterThan(locA1, locB1);
398
399           boolean r2 = isGreaterThan(locA2, locB2);
400
401           if (r1 != r2) {
402             throw new Error("The method " + md1 + " is not consistent with the method " + md2
403                 + ".:: They have a different ordering relation between locations (" + locA1 + ","
404                 + locB1 + ") and (" + locA2 + "," + locB2 + ").");
405           }
406         }
407       }
408     }
409
410   }
411
412   private String getSymbol(int idx, FlowNode node) {
413     Descriptor desc = node.getDescTuple().get(idx);
414     return desc.getSymbol();
415   }
416
417   private Descriptor getDescriptor(int idx, FlowNode node) {
418     Descriptor desc = node.getDescTuple().get(idx);
419     return desc;
420   }
421
422   private void analyzeMethodLattice(MethodDescriptor md, SSJavaLattice<String> methodLattice,
423       MethodLocationInfo methodInfo) {
424
425     // first take a look at method invocation nodes to newly added relations
426     // from the callee
427     analyzeLatticeMethodInvocationNode(md, methodLattice, methodInfo);
428
429     if (!md.isStatic()) {
430       // set the this location
431       String thisLocSymbol = md.getThis().getSymbol();
432       methodInfo.setThisLocName(thisLocSymbol);
433     }
434
435     // set the global location
436     methodInfo.setGlobalLocName(LocationInference.GLOBALLOC);
437
438     // visit each node of method flow graph
439     FlowGraph fg = getFlowGraph(md);
440     Set<FlowNode> nodeSet = fg.getNodeSet();
441
442     // for the method lattice, we need to look at the first element of
443     // NTuple<Descriptor>
444     for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
445       FlowNode srcNode = (FlowNode) iterator.next();
446
447       Set<FlowEdge> outEdgeSet = srcNode.getOutEdgeSet();
448       for (Iterator iterator2 = outEdgeSet.iterator(); iterator2.hasNext();) {
449         FlowEdge outEdge = (FlowEdge) iterator2.next();
450         FlowNode dstNode = outEdge.getDst();
451
452         NTuple<Descriptor> srcNodeTuple = srcNode.getDescTuple();
453         NTuple<Descriptor> dstNodeTuple = dstNode.getDescTuple();
454
455         if (outEdge.getInitTuple().equals(srcNodeTuple)
456             && outEdge.getEndTuple().equals(dstNodeTuple)) {
457
458           if ((srcNodeTuple.size() > 1 && dstNodeTuple.size() > 1)
459               && srcNodeTuple.get(0).equals(dstNodeTuple.get(0))) {
460
461             // value flows between fields
462             VarDescriptor varDesc = (VarDescriptor) srcNodeTuple.get(0);
463             ClassDescriptor varClassDesc = varDesc.getType().getClassDesc();
464             extractRelationFromFieldFlows(varClassDesc, srcNode, dstNode, 1);
465
466           } else if (srcNodeTuple.size() == 1 || dstNodeTuple.size() == 1) {
467             // for the method lattice, we need to look at the first element of
468             // NTuple<Descriptor>
469             // in this case, take a look at connected nodes at the local level
470             addRelationToLattice(md, methodLattice, methodInfo, srcNode, dstNode);
471           } else {
472
473             if (!srcNode.getDescTuple().get(0).equals(dstNode.getDescTuple().get(0))) {
474               // in this case, take a look at connected nodes at the local level
475               addRelationToLattice(md, methodLattice, methodInfo, srcNode, dstNode);
476             } else {
477               Descriptor srcDesc = srcNode.getDescTuple().get(0);
478               Descriptor dstDesc = dstNode.getDescTuple().get(0);
479               recursivelyAddCompositeRelation(md, fg, methodInfo, srcNode, dstNode, srcDesc,
480                   dstDesc);
481               // recursiveAddRelationToLattice(1, md, srcNode, dstNode);
482             }
483           }
484
485         }
486       }
487     }
488
489     // create mapping from param idx to inferred composite location
490
491     int offset;
492     if (!md.isStatic()) {
493       // add 'this' reference location
494       offset = 1;
495       methodInfo.addMapParamIdxToInferLoc(0, methodInfo.getInferLocation(md.getThis()));
496     } else {
497       offset = 0;
498     }
499
500     for (int idx = 0; idx < md.numParameters(); idx++) {
501       Descriptor paramDesc = md.getParameter(idx);
502       CompositeLocation inferParamLoc = methodInfo.getInferLocation(paramDesc);
503       methodInfo.addMapParamIdxToInferLoc(idx + offset, inferParamLoc);
504     }
505
506     // calculate the initial program counter location
507     // PC location is higher than location types of all parameters
508     String pcLocSymbol = "PCLOC";
509     Map<Integer, CompositeLocation> mapParamToLoc = methodInfo.getMapParamIdxToInferLoc();
510     Set<Integer> keySet = mapParamToLoc.keySet();
511     for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
512       Integer paramIdx = (Integer) iterator.next();
513       CompositeLocation inferLoc = mapParamToLoc.get(paramIdx);
514       String paramLocLocalSymbol = inferLoc.get(0).getLocIdentifier();
515       if (!methodLattice.isGreaterThan(pcLocSymbol, paramLocLocalSymbol)) {
516         addRelationHigherToLower(methodLattice, methodInfo, pcLocSymbol, paramLocLocalSymbol);
517       }
518     }
519
520     // calculate a return location
521     // the return location type is lower than all parameters
522     if (!md.getReturnType().isVoid()) {
523
524       String returnLocSymbol = "RETURNLOC";
525
526       for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
527         Integer paramIdx = (Integer) iterator.next();
528         CompositeLocation inferLoc = mapParamToLoc.get(paramIdx);
529         String paramLocLocalSymbol = inferLoc.get(0).getLocIdentifier();
530         if (!methodLattice.isGreaterThan(paramLocLocalSymbol, returnLocSymbol)) {
531           addRelationHigherToLower(methodLattice, methodInfo, paramLocLocalSymbol, returnLocSymbol);
532         }
533       }
534     }
535
536   }
537
538   private CompositeLocation getHighestLocation(Collection<CompositeLocation> locSet) {
539
540     Iterator<CompositeLocation> locIter = locSet.iterator();
541
542     CompositeLocation highest = locIter.next();
543
544     for (; locIter.hasNext();) {
545       CompositeLocation loc = (CompositeLocation) locIter.next();
546       if (isGreaterThan(loc, highest)) {
547         highest = loc;
548       }
549     }
550
551     return highest;
552
553   }
554
555   private boolean isGreaterThan(CompositeLocation comp1, CompositeLocation comp2) {
556
557     for (int idx = 0; idx < comp1.getSize(); idx++) {
558       Location loc1 = comp1.get(idx);
559       Location loc2 = comp2.get(idx);
560
561       Descriptor desc1 = loc1.getDescriptor();
562       Descriptor desc2 = loc2.getDescriptor();
563
564       if (!desc1.equals(desc2)) {
565         throw new Error("Fail to compare " + comp1 + " and " + comp2);
566       }
567
568       String symbol1 = loc1.getLocIdentifier();
569       String symbol2 = loc2.getLocIdentifier();
570
571       if (symbol1.equals(symbol2)) {
572         continue;
573       } else if (getLattice(desc1).isGreaterThan(symbol1, symbol2)) {
574         return true;
575       } else {
576         return false;
577       }
578
579     }
580
581     return false;
582   }
583
584   private void recursiveAddRelationToLattice(int idx, MethodDescriptor md,
585       CompositeLocation srcInferLoc, CompositeLocation dstInferLoc) {
586
587     String srcLocSymbol = srcInferLoc.get(idx).getLocIdentifier();
588     String dstLocSymbol = dstInferLoc.get(idx).getLocIdentifier();
589
590     if (srcLocSymbol.equals(dstLocSymbol)) {
591       recursiveAddRelationToLattice(idx + 1, md, srcInferLoc, dstInferLoc);
592     } else {
593
594       Descriptor parentDesc = srcInferLoc.get(idx).getDescriptor();
595       LocationInfo locInfo = getLocationInfo(parentDesc);
596
597       addRelationHigherToLower(getLattice(parentDesc), getLocationInfo(parentDesc), srcLocSymbol,
598           dstLocSymbol);
599     }
600
601   }
602
603   private void analyzeLatticeMethodInvocationNode(MethodDescriptor mdCaller,
604       SSJavaLattice<String> methodLattice, MethodLocationInfo methodInfo) {
605
606     // the transformation for a call site propagates all relations between
607     // parameters from the callee
608     // if the method is virtual, it also grab all relations from any possible
609     // callees
610
611     Set<MethodInvokeNode> setMethodInvokeNode =
612         mapMethodDescriptorToMethodInvokeNodeSet.get(mdCaller);
613
614     if (setMethodInvokeNode != null) {
615
616       for (Iterator iterator = setMethodInvokeNode.iterator(); iterator.hasNext();) {
617         MethodInvokeNode min = (MethodInvokeNode) iterator.next();
618         MethodDescriptor mdCallee = min.getMethod();
619         Set<MethodDescriptor> setPossibleCallees = new HashSet<MethodDescriptor>();
620         if (mdCallee.isStatic()) {
621           setPossibleCallees.add(mdCallee);
622         } else {
623           Set<MethodDescriptor> calleeSet = ssjava.getCallGraph().getMethods(mdCallee);
624           // removes method descriptors that are not invoked by the caller
625           calleeSet.retainAll(mapMethodToCalleeSet.get(mdCaller));
626           setPossibleCallees.addAll(calleeSet);
627         }
628
629         for (Iterator iterator2 = setPossibleCallees.iterator(); iterator2.hasNext();) {
630           MethodDescriptor possibleMdCallee = (MethodDescriptor) iterator2.next();
631           propagateRelationToCaller(min, mdCaller, possibleMdCallee, methodLattice, methodInfo);
632         }
633
634       }
635     }
636
637   }
638
639   private void propagateRelationToCaller(MethodInvokeNode min, MethodDescriptor mdCaller,
640       MethodDescriptor possibleMdCallee, SSJavaLattice<String> methodLattice,
641       MethodLocationInfo methodInfo) {
642
643     SSJavaLattice<String> calleeLattice = getMethodLattice(possibleMdCallee);
644     MethodLocationInfo calleeLocInfo = getMethodLocationInfo(possibleMdCallee);
645     FlowGraph calleeFlowGraph = getFlowGraph(possibleMdCallee);
646
647     int numParam = calleeLocInfo.getNumParam();
648     for (int i = 0; i < numParam; i++) {
649       CompositeLocation param1 = calleeLocInfo.getParamCompositeLocation(i);
650       for (int k = 0; k < numParam; k++) {
651         if (i != k) {
652           CompositeLocation param2 = calleeLocInfo.getParamCompositeLocation(k);
653           if (isGreaterThan(param1, param2)) {
654             NTuple<Descriptor> argDescTuple1 = getArgTupleByArgIdx(min, i);
655             NTuple<Descriptor> argDescTuple2 = getArgTupleByArgIdx(min, k);
656             addRelation(methodLattice, methodInfo, argDescTuple1.get(0), argDescTuple2.get(0));
657           }
658         }
659       }
660     }
661
662   }
663
664   private LocationInfo getLocationInfo(Descriptor d) {
665     if (d instanceof MethodDescriptor) {
666       return getMethodLocationInfo((MethodDescriptor) d);
667     } else {
668       return getFieldLocationInfo((ClassDescriptor) d);
669     }
670   }
671
672   private MethodLocationInfo getMethodLocationInfo(MethodDescriptor md) {
673
674     if (!mapMethodDescToMethodLocationInfo.containsKey(md)) {
675       mapMethodDescToMethodLocationInfo.put(md, new MethodLocationInfo(md));
676     }
677
678     return mapMethodDescToMethodLocationInfo.get(md);
679
680   }
681
682   private LocationInfo getFieldLocationInfo(ClassDescriptor cd) {
683
684     if (!mapClassToLocationInfo.containsKey(cd)) {
685       mapClassToLocationInfo.put(cd, new LocationInfo(cd));
686     }
687
688     return mapClassToLocationInfo.get(cd);
689
690   }
691
692   private void addRelationToLattice(MethodDescriptor md, SSJavaLattice<String> methodLattice,
693       MethodLocationInfo methodInfo, FlowNode srcNode, FlowNode dstNode) {
694
695     System.out.println();
696     System.out.println("### addRelationToLattice src=" + srcNode + " dst=" + dstNode);
697
698     // add a new binary relation of dstNode < srcNode
699     FlowGraph flowGraph = getFlowGraph(md);
700
701     Descriptor srcDesc = getDescriptor(0, srcNode);
702     Descriptor dstDesc = getDescriptor(0, dstNode);
703
704     // boolean isAssignedCompositeLocation = false;
705     // if (!methodInfo.getInferLocation(srcDesc).get(0).getLocIdentifier()
706     // .equals(methodInfo.getThisLocName())) {
707     // isAssignedCompositeLocation =
708     calculateCompositeLocation(flowGraph, methodLattice, methodInfo, srcNode);
709     // }
710
711     String srcSymbol = methodInfo.getInferLocation(srcDesc).get(0).getLocIdentifier();
712     String dstSymbol = methodInfo.getInferLocation(dstDesc).get(0).getLocIdentifier();
713
714     // if (srcNode.isParameter()) {
715     // int paramIdx = flowGraph.getParamIdx(srcNode.getDescTuple());
716     // methodInfo.addParameter(srcSymbol, srcDesc, paramIdx);
717     // }
718     //
719     // if (dstNode.isParameter()) {
720     // int paramIdx = flowGraph.getParamIdx(dstNode.getDescTuple());
721     // methodInfo.addParameter(dstSymbol, dstDesc, paramIdx);
722     // }
723
724     CompositeLocation srcInferLoc = methodInfo.getInferLocation(srcDesc);
725     CompositeLocation dstInferLoc = methodInfo.getInferLocation(dstDesc);
726
727     String srcLocalLocSymbol = srcInferLoc.get(0).getLocIdentifier();
728     String dstLocalLocSymbol = dstInferLoc.get(0).getLocIdentifier();
729
730     if (srcInferLoc.getSize() == 1 && dstInferLoc.getSize() == 1) {
731       // add a new relation to the local lattice
732       addRelationHigherToLower(methodLattice, methodInfo, srcLocalLocSymbol, dstLocalLocSymbol);
733     } else if (srcInferLoc.getSize() > 1 && dstInferLoc.getSize() > 1) {
734       // both src and dst have assigned to a composite location
735       recursivelyAddRelation(1, srcInferLoc, dstInferLoc);
736     } else {
737       // either src or dst has assigned to a composite location
738       if (!srcLocalLocSymbol.equals(dstLocalLocSymbol)) {
739         addRelationHigherToLower(methodLattice, methodInfo, srcLocalLocSymbol, dstLocalLocSymbol);
740       }
741     }
742     // if (!isAssignedCompositeLocation) {
743     // // source does not have a composite location
744     //
745     // NTuple<Location> srcTuple = flowGraph.getLocationTuple(srcNode);
746     // NTuple<Location> dstTuple = flowGraph.getLocationTuple(dstNode);
747     //
748     // recursivelyAddCompositeRelation(md, flowGraph, methodInfo, srcNode,
749     // dstNode, srcDesc, dstDSSJavaLattice<String> methodLattice,
750     //
751     // // if (!srcSymbol.equals(dstSymbol)) {
752     // // // add a local relation
753     // // if (!methodLattice.isGreaterThan(srcSymbol, dstSymbol)) {
754     // // // if the lattice does not have this relation, add it
755     // // addRelationHigherToLower(methodLattice, methodInfo, srcSymbol,
756     // // dstSymbol);
757     // // // methodLattice.addRelationHigherToLower(srcSymbol, dstSymbol);
758     // // }
759     // // } else {
760     // // // if src and dst have the same local location...
761     // // recursivelyAddCompositeRelation(md, flowGraph, methodInfo, srcNode,
762     // // dstNode, srcDesc,
763     // // dstDesc);
764     // // }
765     //
766     // } else {
767     // // source variable has a composite location
768     // if (methodInfo.getInferLocation(dstDesc).getSize() == 1) {
769     // if (!srcSymbol.equals(dstSymbol)) {
770     // addRelationHigherToLower(methodLattice, methodInfo, srcSymbol,
771     // dstSymbol);
772     // }
773     // }
774     //
775     // }
776
777   }
778
779   private void addRelation(SSJavaLattice<String> methodLattice, MethodLocationInfo methodInfo,
780       Descriptor srcDesc, Descriptor dstDesc) {
781
782     CompositeLocation srcInferLoc = methodInfo.getInferLocation(srcDesc);
783     CompositeLocation dstInferLoc = methodInfo.getInferLocation(dstDesc);
784
785     String srcLocalLocSymbol = srcInferLoc.get(0).getLocIdentifier();
786     String dstLocalLocSymbol = dstInferLoc.get(0).getLocIdentifier();
787
788     if (srcInferLoc.getSize() == 1 && dstInferLoc.getSize() == 1) {
789       // add a new relation to the local lattice
790       addRelationHigherToLower(methodLattice, methodInfo, srcLocalLocSymbol, dstLocalLocSymbol);
791     } else if (srcInferLoc.getSize() > 1 && dstInferLoc.getSize() > 1) {
792       // both src and dst have assigned to a composite location
793       recursivelyAddRelation(1, srcInferLoc, dstInferLoc);
794     } else {
795       // either src or dst has assigned to a composite location
796       if (!srcLocalLocSymbol.equals(dstLocalLocSymbol)) {
797         addRelationHigherToLower(methodLattice, methodInfo, srcLocalLocSymbol, dstLocalLocSymbol);
798       }
799     }
800   }
801
802   private void recursivelyAddRelation(int idx, CompositeLocation srcInferLoc,
803       CompositeLocation dstInferLoc) {
804
805     String srcLocSymbol = srcInferLoc.get(idx).getLocIdentifier();
806     String dstLocSymbol = dstInferLoc.get(idx).getLocIdentifier();
807
808     if (srcLocSymbol.equals(dstLocSymbol)) {
809       recursivelyAddRelation(idx + 1, srcInferLoc, dstInferLoc);
810     } else {
811
812       Descriptor parentDesc = srcInferLoc.get(idx).getDescriptor();
813
814       addRelationHigherToLower(getLattice(parentDesc), getLocationInfo(parentDesc), srcLocSymbol,
815           dstLocSymbol);
816     }
817
818   }
819
820   private void recursivelyAddCompositeRelation(MethodDescriptor md, FlowGraph flowGraph,
821       MethodLocationInfo methodInfo, FlowNode srcNode, FlowNode dstNode, Descriptor srcDesc,
822       Descriptor dstDesc) {
823
824     CompositeLocation inferSrcLoc;
825     CompositeLocation inferDstLoc = methodInfo.getInferLocation(dstDesc);
826
827     if (srcNode.getDescTuple().size() > 1) {
828       // field access
829       inferSrcLoc = new CompositeLocation();
830
831       NTuple<Location> locTuple = flowGraph.getLocationTuple(srcNode);
832       for (int i = 0; i < locTuple.size(); i++) {
833         inferSrcLoc.addLocation(locTuple.get(i));
834       }
835
836     } else {
837       inferSrcLoc = methodInfo.getInferLocation(srcDesc);
838     }
839
840     if (dstNode.getDescTuple().size() > 1) {
841       // field access
842       inferDstLoc = new CompositeLocation();
843
844       NTuple<Location> locTuple = flowGraph.getLocationTuple(dstNode);
845       for (int i = 0; i < locTuple.size(); i++) {
846         inferDstLoc.addLocation(locTuple.get(i));
847       }
848
849     } else {
850       inferDstLoc = methodInfo.getInferLocation(dstDesc);
851     }
852
853     recursiveAddRelationToLattice(1, md, inferSrcLoc, inferDstLoc);
854   }
855
856   private void addPrefixMapping(Map<NTuple<Location>, Set<NTuple<Location>>> map,
857       NTuple<Location> prefix, NTuple<Location> element) {
858
859     if (!map.containsKey(prefix)) {
860       map.put(prefix, new HashSet<NTuple<Location>>());
861     }
862     map.get(prefix).add(element);
863   }
864
865   private boolean calculateCompositeLocation(FlowGraph flowGraph,
866       SSJavaLattice<String> methodLattice, MethodLocationInfo methodInfo, FlowNode flowNode) {
867
868     Descriptor localVarDesc = flowNode.getDescTuple().get(0);
869
870     Set<FlowNode> inNodeSet = flowGraph.getIncomingFlowNodeSet(flowNode);
871     Set<FlowNode> reachableNodeSet = flowGraph.getReachableFlowNodeSet(flowNode);
872
873     Map<NTuple<Location>, Set<NTuple<Location>>> mapPrefixToIncomingLocTupleSet =
874         new HashMap<NTuple<Location>, Set<NTuple<Location>>>();
875
876     Set<FlowNode> localInNodeSet = new HashSet<FlowNode>();
877     Set<FlowNode> localOutNodeSet = new HashSet<FlowNode>();
878
879     List<NTuple<Location>> prefixList = new ArrayList<NTuple<Location>>();
880
881     for (Iterator iterator = inNodeSet.iterator(); iterator.hasNext();) {
882       FlowNode inNode = (FlowNode) iterator.next();
883       NTuple<Location> inTuple = flowGraph.getLocationTuple(inNode);
884
885       if (inTuple.size() > 1) {
886         for (int i = 1; i < inTuple.size(); i++) {
887           NTuple<Location> prefix = inTuple.subList(0, i);
888           if (!prefixList.contains(prefix)) {
889             prefixList.add(prefix);
890           }
891           addPrefixMapping(mapPrefixToIncomingLocTupleSet, prefix, inTuple);
892         }
893       } else {
894         localInNodeSet.add(inNode);
895       }
896     }
897
898     Collections.sort(prefixList, new Comparator<NTuple<Location>>() {
899       public int compare(NTuple<Location> arg0, NTuple<Location> arg1) {
900         int s0 = arg0.size();
901         int s1 = arg1.size();
902         if (s0 > s1) {
903           return -1;
904         } else if (s0 == s1) {
905           return 0;
906         } else {
907           return 1;
908         }
909       }
910     });
911
912     for (Iterator iterator2 = reachableNodeSet.iterator(); iterator2.hasNext();) {
913       FlowNode reachableNode = (FlowNode) iterator2.next();
914       if (reachableNode.getDescTuple().size() == 1) {
915         localOutNodeSet.add(reachableNode);
916       }
917     }
918
919     // find out reachable nodes that have the longest common prefix
920     for (int i = 0; i < prefixList.size(); i++) {
921       NTuple<Location> curPrefix = prefixList.get(i);
922       Set<NTuple<Location>> reachableCommonPrefixSet = new HashSet<NTuple<Location>>();
923
924       for (Iterator iterator2 = reachableNodeSet.iterator(); iterator2.hasNext();) {
925         FlowNode reachableNode = (FlowNode) iterator2.next();
926         NTuple<Location> reachLocTuple = flowGraph.getLocationTuple(reachableNode);
927         if (reachLocTuple.startsWith(curPrefix)) {
928           reachableCommonPrefixSet.add(reachLocTuple);
929         }
930
931       }
932
933       if (!reachableCommonPrefixSet.isEmpty()) {
934         // found reachable nodes that start with the prefix curPrefix
935         // need to assign a composite location
936
937         // first, check if there are more than one the set of locations that has
938         // the same length of the longest reachable prefix, no way to assign
939         // a composite location to the input local var
940         prefixSanityCheck(prefixList, i, flowGraph, reachableNodeSet);
941
942         Set<NTuple<Location>> incomingCommonPrefixSet =
943             mapPrefixToIncomingLocTupleSet.get(curPrefix);
944
945         int idx = curPrefix.size();
946         NTuple<Location> element = incomingCommonPrefixSet.iterator().next();
947         Descriptor desc = element.get(idx).getDescriptor();
948
949         SSJavaLattice<String> lattice = getLattice(desc);
950         LocationInfo locInfo = getLocationInfo(desc);
951
952         // CompositeLocation inferLocation =
953         // methodInfo.getInferLocation(flowNode);
954         CompositeLocation inferLocation = methodInfo.getInferLocation(localVarDesc);
955
956         String newlyInsertedLocName;
957         if (inferLocation.getSize() == 1) {
958           // need to replace the old local location with a new composite
959           // location
960
961           String oldMethodLocationSymbol = inferLocation.get(0).getLocIdentifier();
962
963           String newLocSymbol = "Loc" + (SSJavaLattice.seed++);
964           inferLocation = new CompositeLocation();
965           for (int locIdx = 0; locIdx < curPrefix.size(); locIdx++) {
966             inferLocation.addLocation(curPrefix.get(locIdx));
967           }
968           Location fieldLoc = new Location(desc, newLocSymbol);
969           inferLocation.addLocation(fieldLoc);
970
971           methodInfo.mapDescriptorToLocation(localVarDesc, inferLocation);
972           methodInfo.removeMaplocalVarToLocSet(localVarDesc);
973
974           String newMethodLocationSymbol = curPrefix.get(0).getLocIdentifier();
975
976           replaceOldLocWithNewLoc(methodLattice, oldMethodLocationSymbol, newMethodLocationSymbol);
977
978         } else {
979
980           String localLocName = methodInfo.getInferLocation(localVarDesc).get(0).getLocIdentifier();
981           return true;
982
983         }
984
985         newlyInsertedLocName = inferLocation.get(inferLocation.getSize() - 1).getLocIdentifier();
986
987         for (Iterator iterator = incomingCommonPrefixSet.iterator(); iterator.hasNext();) {
988           NTuple<Location> tuple = (NTuple<Location>) iterator.next();
989
990           Location loc = tuple.get(idx);
991           String higher = locInfo.getFieldInferLocation(loc.getLocDescriptor()).getLocIdentifier();
992           System.out.println("--");
993           System.out.println("add in-flow relation:");
994           addRelationHigherToLower(lattice, locInfo, higher, newlyInsertedLocName);
995         }
996         System.out.println("end of add-inflow relation");
997
998         for (Iterator iterator = localInNodeSet.iterator(); iterator.hasNext();) {
999           FlowNode localNode = (FlowNode) iterator.next();
1000           Descriptor localInVarDesc = localNode.getDescTuple().get(0);
1001           CompositeLocation inNodeInferLoc = methodInfo.getInferLocation(localInVarDesc);
1002
1003           if (isCompositeLocation(inNodeInferLoc)) {
1004             // need to make sure that newLocSymbol is lower than the infernode
1005             // location in the field lattice
1006
1007             if (inNodeInferLoc.getTuple().startsWith(curPrefix)
1008                 && inNodeInferLoc.getSize() == (curPrefix.size() + 1)) {
1009               String higher = inNodeInferLoc.get(inNodeInferLoc.getSize() - 1).getLocIdentifier();
1010               if (!higher.equals(newlyInsertedLocName)) {
1011                 System.out.println("add localInNodeSet relation:");
1012                 addRelationHigherToLower(lattice, locInfo, higher, newlyInsertedLocName);
1013               }
1014             } else {
1015               throw new Error("Failed to generate a composite location.");
1016             }
1017
1018           }
1019         }
1020
1021         for (Iterator iterator = reachableCommonPrefixSet.iterator(); iterator.hasNext();) {
1022           NTuple<Location> tuple = (NTuple<Location>) iterator.next();
1023           Location loc = tuple.get(idx);
1024           String lower = locInfo.getFieldInferLocation(loc.getLocDescriptor()).getLocIdentifier();
1025           // lattice.addRelationHigherToLower(newlyInsertedLocName, lower);
1026           System.out.println("add out-flow relation:");
1027           addRelationHigherToLower(lattice, locInfo, newlyInsertedLocName, lower);
1028         }
1029         System.out.println("end of add out-flow relation");
1030
1031         for (Iterator iterator = localOutNodeSet.iterator(); iterator.hasNext();) {
1032           FlowNode localOutNode = (FlowNode) iterator.next();
1033
1034           Descriptor localOutDesc = localOutNode.getDescTuple().get(0);
1035           // String localOutNodeSymbol =
1036           // localOutNode.getDescTuple().get(0).getSymbol();
1037           CompositeLocation outNodeInferLoc = methodInfo.getInferLocation(localOutDesc);
1038
1039           // System.out
1040           // .println("localOutNode=" + localOutNode + " outNodeInferLoc=" +
1041           // outNodeInferLoc);
1042           if (isCompositeLocation(outNodeInferLoc)) {
1043             // need to make sure that newLocSymbol is higher than the infernode
1044             // location
1045
1046             if (outNodeInferLoc.getTuple().startsWith(curPrefix)
1047                 && outNodeInferLoc.getSize() == (curPrefix.size() + 1)) {
1048
1049               String lower = outNodeInferLoc.get(outNodeInferLoc.getSize() - 1).getLocIdentifier();
1050               System.out.println("add outNodeInferLoc relation:");
1051
1052               addRelationHigherToLower(lattice, locInfo, newlyInsertedLocName, lower);
1053
1054             } else {
1055               throw new Error("Failed to generate a composite location.");
1056             }
1057           }
1058         }
1059
1060         return true;
1061       }
1062
1063     }
1064
1065     return false;
1066
1067   }
1068
1069   private boolean isCompositeLocation(CompositeLocation cl) {
1070     return cl.getSize() > 1;
1071   }
1072
1073   private boolean containsNonPrimitiveElement(Set<Descriptor> descSet) {
1074     for (Iterator iterator = descSet.iterator(); iterator.hasNext();) {
1075       Descriptor desc = (Descriptor) iterator.next();
1076
1077       if (desc.equals(LocationInference.GLOBALDESC)) {
1078         return true;
1079       } else if (desc instanceof VarDescriptor) {
1080         if (!((VarDescriptor) desc).getType().isPrimitive()) {
1081           return true;
1082         }
1083       } else if (desc instanceof FieldDescriptor) {
1084         if (!((FieldDescriptor) desc).getType().isPrimitive()) {
1085           return true;
1086         }
1087       }
1088
1089     }
1090     return false;
1091   }
1092
1093   private void addRelationHigherToLower(SSJavaLattice<String> lattice, LocationInfo locInfo,
1094       String higher, String lower) {
1095
1096     // if (higher.equals(lower) && lattice.isSharedLoc(higher)) {
1097     // return;
1098     // }
1099
1100     Set<String> cycleElementSet = lattice.getPossibleCycleElements(higher, lower);
1101     System.out.println("#Check cycle=" + lower + " < " + higher);
1102     System.out.println("#cycleElementSet=" + cycleElementSet);
1103
1104     boolean hasNonPrimitiveElement = false;
1105     for (Iterator iterator = cycleElementSet.iterator(); iterator.hasNext();) {
1106       String cycleElementLocSymbol = (String) iterator.next();
1107
1108       Set<Descriptor> descSet = locInfo.getDescSet(cycleElementLocSymbol);
1109       if (containsNonPrimitiveElement(descSet)) {
1110         hasNonPrimitiveElement = true;
1111         break;
1112       }
1113     }
1114
1115     if (hasNonPrimitiveElement) {
1116       // if there is non-primitive element in the cycle, no way to merge cyclic
1117       // elements into the shared location
1118       throw new Error("Failed to merge cyclic value flows into a shared location.");
1119     }
1120
1121     if (cycleElementSet.size() > 0) {
1122       String newSharedLoc = "SharedLoc" + (SSJavaLattice.seed++);
1123
1124       lattice.mergeIntoSharedLocation(cycleElementSet, newSharedLoc);
1125
1126       for (Iterator iterator = cycleElementSet.iterator(); iterator.hasNext();) {
1127         String oldLocSymbol = (String) iterator.next();
1128         locInfo.mergeMapping(oldLocSymbol, newSharedLoc);
1129       }
1130
1131       lattice.addSharedLoc(newSharedLoc);
1132
1133     } else if (!lattice.isGreaterThan(higher, lower)) {
1134       lattice.addRelationHigherToLower(higher, lower);
1135     }
1136   }
1137
1138   private void replaceOldLocWithNewLoc(SSJavaLattice<String> methodLattice, String oldLocSymbol,
1139       String newLocSymbol) {
1140
1141     if (methodLattice.containsKey(oldLocSymbol)) {
1142       methodLattice.substituteLocation(oldLocSymbol, newLocSymbol);
1143     }
1144
1145   }
1146
1147   private void prefixSanityCheck(List<NTuple<Location>> prefixList, int curIdx,
1148       FlowGraph flowGraph, Set<FlowNode> reachableNodeSet) {
1149
1150     NTuple<Location> curPrefix = prefixList.get(curIdx);
1151
1152     for (int i = curIdx + 1; i < prefixList.size(); i++) {
1153       NTuple<Location> prefixTuple = prefixList.get(i);
1154
1155       if (curPrefix.startsWith(prefixTuple)) {
1156         continue;
1157       }
1158
1159       for (Iterator iterator2 = reachableNodeSet.iterator(); iterator2.hasNext();) {
1160         FlowNode reachableNode = (FlowNode) iterator2.next();
1161         NTuple<Location> reachLocTuple = flowGraph.getLocationTuple(reachableNode);
1162         if (reachLocTuple.startsWith(prefixTuple)) {
1163           // TODO
1164           throw new Error("Failed to generate a composite location");
1165         }
1166       }
1167     }
1168   }
1169
1170   public boolean isPrimitiveLocalVariable(FlowNode node) {
1171     VarDescriptor varDesc = (VarDescriptor) node.getDescTuple().get(0);
1172     return varDesc.getType().isPrimitive();
1173   }
1174
1175   private SSJavaLattice<String> getLattice(Descriptor d) {
1176     if (d instanceof MethodDescriptor) {
1177       return getMethodLattice((MethodDescriptor) d);
1178     } else {
1179       return getFieldLattice((ClassDescriptor) d);
1180     }
1181   }
1182
1183   private SSJavaLattice<String> getMethodLattice(MethodDescriptor md) {
1184     if (!md2lattice.containsKey(md)) {
1185       md2lattice.put(md, new SSJavaLattice<String>(SSJavaAnalysis.TOP, SSJavaAnalysis.BOTTOM));
1186     }
1187     return md2lattice.get(md);
1188   }
1189
1190   private void setMethodLattice(MethodDescriptor md, SSJavaLattice<String> lattice) {
1191     md2lattice.put(md, lattice);
1192   }
1193
1194   private void extractRelationFromFieldFlows(ClassDescriptor cd, FlowNode srcNode,
1195       FlowNode dstNode, int idx) {
1196
1197     if (srcNode.getDescTuple().get(idx).equals(dstNode.getDescTuple().get(idx))
1198         && srcNode.getDescTuple().size() > (idx + 1) && dstNode.getDescTuple().size() > (idx + 1)) {
1199       // value flow between fields: we don't need to add a binary relation
1200       // for this case
1201
1202       Descriptor desc = srcNode.getDescTuple().get(idx);
1203       ClassDescriptor classDesc;
1204
1205       if (idx == 0) {
1206         classDesc = ((VarDescriptor) desc).getType().getClassDesc();
1207       } else {
1208         classDesc = ((FieldDescriptor) desc).getType().getClassDesc();
1209       }
1210
1211       extractRelationFromFieldFlows(classDesc, srcNode, dstNode, idx + 1);
1212
1213     } else {
1214
1215       Descriptor srcFieldDesc = srcNode.getDescTuple().get(idx);
1216       Descriptor dstFieldDesc = dstNode.getDescTuple().get(idx);
1217
1218       // add a new binary relation of dstNode < srcNode
1219       SSJavaLattice<String> fieldLattice = getFieldLattice(cd);
1220       LocationInfo fieldInfo = getFieldLocationInfo(cd);
1221
1222       String srcSymbol = fieldInfo.getFieldInferLocation(srcFieldDesc).getLocIdentifier();
1223       String dstSymbol = fieldInfo.getFieldInferLocation(dstFieldDesc).getLocIdentifier();
1224
1225       addRelationHigherToLower(fieldLattice, fieldInfo, srcSymbol, dstSymbol);
1226
1227     }
1228
1229   }
1230
1231   public SSJavaLattice<String> getFieldLattice(ClassDescriptor cd) {
1232     if (!cd2lattice.containsKey(cd)) {
1233       cd2lattice.put(cd, new SSJavaLattice<String>(SSJavaAnalysis.TOP, SSJavaAnalysis.BOTTOM));
1234     }
1235     return cd2lattice.get(cd);
1236   }
1237
1238   public void constructFlowGraph() {
1239
1240     setupToAnalyze();
1241
1242     Set<MethodDescriptor> visited = new HashSet<MethodDescriptor>();
1243     Set<MethodDescriptor> reachableCallee = new HashSet<MethodDescriptor>();
1244
1245     while (!toAnalyzeIsEmpty()) {
1246       ClassDescriptor cd = toAnalyzeNext();
1247
1248       setupToAnalazeMethod(cd);
1249       toanalyzeMethodList.removeAll(visited);
1250
1251       while (!toAnalyzeMethodIsEmpty()) {
1252         MethodDescriptor md = toAnalyzeMethodNext();
1253         if ((!visited.contains(md))
1254             && (ssjava.needTobeAnnotated(md) || reachableCallee.contains(md))) {
1255           if (state.SSJAVADEBUG) {
1256             System.out.println();
1257             System.out.println("SSJAVA: Constructing a flow graph: " + md);
1258           }
1259
1260           // creates a mapping from a method descriptor to virtual methods
1261           Set<MethodDescriptor> setPossibleCallees = new HashSet<MethodDescriptor>();
1262           if (md.isStatic()) {
1263             setPossibleCallees.add(md);
1264           } else {
1265             setPossibleCallees.addAll(ssjava.getCallGraph().getMethods(md));
1266           }
1267
1268           Set<MethodDescriptor> calleeSet = ssjava.getCallGraph().getCalleeSet(md);
1269           Set<MethodDescriptor> needToAnalyzeCalleeSet = new HashSet<MethodDescriptor>();
1270
1271           for (Iterator iterator = calleeSet.iterator(); iterator.hasNext();) {
1272             MethodDescriptor calleemd = (MethodDescriptor) iterator.next();
1273             if ((!ssjava.isTrustMethod(calleemd))
1274                 && (!ssjava.isSSJavaUtil(calleemd.getClassDesc()))) {
1275               if (!visited.contains(calleemd)) {
1276                 toanalyzeMethodList.add(calleemd);
1277               }
1278               reachableCallee.add(calleemd);
1279               needToAnalyzeCalleeSet.add(calleemd);
1280             }
1281           }
1282
1283           mapMethodToCalleeSet.put(md, needToAnalyzeCalleeSet);
1284
1285           // creates a mapping from a parameter descriptor to its index
1286           Map<Descriptor, Integer> mapParamDescToIdx = new HashMap<Descriptor, Integer>();
1287           int offset = md.isStatic() ? 0 : 1;
1288           for (int i = 0; i < md.numParameters(); i++) {
1289             Descriptor paramDesc = (Descriptor) md.getParameter(i);
1290             mapParamDescToIdx.put(paramDesc, new Integer(i + offset));
1291           }
1292
1293           FlowGraph fg = new FlowGraph(md, mapParamDescToIdx);
1294           mapMethodDescriptorToFlowGraph.put(md, fg);
1295
1296           visited.add(md);
1297           analyzeMethodBody(cd, md);
1298
1299         }
1300       }
1301     }
1302
1303     _debug_printGraph();
1304   }
1305
1306   private void analyzeMethodBody(ClassDescriptor cd, MethodDescriptor md) {
1307     BlockNode bn = state.getMethodBody(md);
1308     NodeTupleSet implicitFlowTupleSet = new NodeTupleSet();
1309     analyzeFlowBlockNode(md, md.getParameterTable(), bn, implicitFlowTupleSet);
1310   }
1311
1312   private void analyzeFlowBlockNode(MethodDescriptor md, SymbolTable nametable, BlockNode bn,
1313       NodeTupleSet implicitFlowTupleSet) {
1314
1315     bn.getVarTable().setParent(nametable);
1316     for (int i = 0; i < bn.size(); i++) {
1317       BlockStatementNode bsn = bn.get(i);
1318       analyzeBlockStatementNode(md, bn.getVarTable(), bsn, implicitFlowTupleSet);
1319     }
1320
1321   }
1322
1323   private void analyzeBlockStatementNode(MethodDescriptor md, SymbolTable nametable,
1324       BlockStatementNode bsn, NodeTupleSet implicitFlowTupleSet) {
1325
1326     switch (bsn.kind()) {
1327     case Kind.BlockExpressionNode:
1328       analyzeBlockExpressionNode(md, nametable, (BlockExpressionNode) bsn, implicitFlowTupleSet);
1329       break;
1330
1331     case Kind.DeclarationNode:
1332       analyzeFlowDeclarationNode(md, nametable, (DeclarationNode) bsn, implicitFlowTupleSet);
1333       break;
1334
1335     case Kind.IfStatementNode:
1336       analyzeFlowIfStatementNode(md, nametable, (IfStatementNode) bsn, implicitFlowTupleSet);
1337       break;
1338
1339     case Kind.LoopNode:
1340       analyzeFlowLoopNode(md, nametable, (LoopNode) bsn, implicitFlowTupleSet);
1341       break;
1342
1343     case Kind.ReturnNode:
1344       analyzeFlowReturnNode(md, nametable, (ReturnNode) bsn, implicitFlowTupleSet);
1345       break;
1346
1347     case Kind.SubBlockNode:
1348       analyzeFlowSubBlockNode(md, nametable, (SubBlockNode) bsn, implicitFlowTupleSet);
1349       break;
1350
1351     case Kind.ContinueBreakNode:
1352       break;
1353
1354     case Kind.SwitchStatementNode:
1355       analyzeSwitchStatementNode(md, nametable, (SwitchStatementNode) bsn);
1356       break;
1357
1358     }
1359
1360   }
1361
1362   private void analyzeSwitchStatementNode(MethodDescriptor md, SymbolTable nametable,
1363       SwitchStatementNode bsn) {
1364     // TODO Auto-generated method stub
1365   }
1366
1367   private void analyzeFlowSubBlockNode(MethodDescriptor md, SymbolTable nametable,
1368       SubBlockNode sbn, NodeTupleSet implicitFlowTupleSet) {
1369     analyzeFlowBlockNode(md, nametable, sbn.getBlockNode(), implicitFlowTupleSet);
1370   }
1371
1372   private void analyzeFlowReturnNode(MethodDescriptor md, SymbolTable nametable, ReturnNode rn,
1373       NodeTupleSet implicitFlowTupleSet) {
1374
1375     ExpressionNode returnExp = rn.getReturnExpression();
1376
1377     if (returnExp != null) {
1378       NodeTupleSet nodeSet = new NodeTupleSet();
1379       analyzeFlowExpressionNode(md, nametable, returnExp, nodeSet, false);
1380
1381       FlowGraph fg = getFlowGraph(md);
1382
1383       // annotate the elements of the node set as the return location
1384       for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
1385         NTuple<Descriptor> returnDescTuple = (NTuple<Descriptor>) iterator.next();
1386         fg.setReturnFlowNode(returnDescTuple);
1387         for (Iterator iterator2 = implicitFlowTupleSet.iterator(); iterator2.hasNext();) {
1388           NTuple<Descriptor> implicitFlowDescTuple = (NTuple<Descriptor>) iterator2.next();
1389           fg.addValueFlowEdge(implicitFlowDescTuple, returnDescTuple);
1390         }
1391       }
1392     }
1393
1394   }
1395
1396   private void analyzeFlowLoopNode(MethodDescriptor md, SymbolTable nametable, LoopNode ln,
1397       NodeTupleSet implicitFlowTupleSet) {
1398
1399     if (ln.getType() == LoopNode.WHILELOOP || ln.getType() == LoopNode.DOWHILELOOP) {
1400
1401       NodeTupleSet condTupleNode = new NodeTupleSet();
1402       analyzeFlowExpressionNode(md, nametable, ln.getCondition(), condTupleNode, null,
1403           implicitFlowTupleSet, false);
1404       condTupleNode.addTupleSet(implicitFlowTupleSet);
1405
1406       // add edges from condNodeTupleSet to all nodes of conditional nodes
1407       analyzeFlowBlockNode(md, nametable, ln.getBody(), condTupleNode);
1408
1409     } else {
1410       // check 'for loop' case
1411       BlockNode bn = ln.getInitializer();
1412       bn.getVarTable().setParent(nametable);
1413       for (int i = 0; i < bn.size(); i++) {
1414         BlockStatementNode bsn = bn.get(i);
1415         analyzeBlockStatementNode(md, bn.getVarTable(), bsn, implicitFlowTupleSet);
1416       }
1417
1418       NodeTupleSet condTupleNode = new NodeTupleSet();
1419       analyzeFlowExpressionNode(md, bn.getVarTable(), ln.getCondition(), condTupleNode, null,
1420           implicitFlowTupleSet, false);
1421       condTupleNode.addTupleSet(implicitFlowTupleSet);
1422
1423       analyzeFlowBlockNode(md, bn.getVarTable(), ln.getUpdate(), condTupleNode);
1424       analyzeFlowBlockNode(md, bn.getVarTable(), ln.getBody(), condTupleNode);
1425
1426     }
1427
1428   }
1429
1430   private void analyzeFlowIfStatementNode(MethodDescriptor md, SymbolTable nametable,
1431       IfStatementNode isn, NodeTupleSet implicitFlowTupleSet) {
1432
1433     NodeTupleSet condTupleNode = new NodeTupleSet();
1434     analyzeFlowExpressionNode(md, nametable, isn.getCondition(), condTupleNode, null,
1435         implicitFlowTupleSet, false);
1436
1437     // add edges from condNodeTupleSet to all nodes of conditional nodes
1438     condTupleNode.addTupleSet(implicitFlowTupleSet);
1439     analyzeFlowBlockNode(md, nametable, isn.getTrueBlock(), condTupleNode);
1440
1441     if (isn.getFalseBlock() != null) {
1442       analyzeFlowBlockNode(md, nametable, isn.getFalseBlock(), condTupleNode);
1443     }
1444
1445   }
1446
1447   private void analyzeFlowDeclarationNode(MethodDescriptor md, SymbolTable nametable,
1448       DeclarationNode dn, NodeTupleSet implicitFlowTupleSet) {
1449
1450     VarDescriptor vd = dn.getVarDescriptor();
1451     NTuple<Descriptor> tupleLHS = new NTuple<Descriptor>();
1452     tupleLHS.add(vd);
1453     getFlowGraph(md).createNewFlowNode(tupleLHS);
1454
1455     if (dn.getExpression() != null) {
1456
1457       NodeTupleSet tupleSetRHS = new NodeTupleSet();
1458       analyzeFlowExpressionNode(md, nametable, dn.getExpression(), tupleSetRHS, null,
1459           implicitFlowTupleSet, false);
1460
1461       // add a new flow edge from rhs to lhs
1462       for (Iterator<NTuple<Descriptor>> iter = tupleSetRHS.iterator(); iter.hasNext();) {
1463         NTuple<Descriptor> from = iter.next();
1464         addFlowGraphEdge(md, from, tupleLHS);
1465       }
1466
1467     }
1468
1469   }
1470
1471   private void analyzeBlockExpressionNode(MethodDescriptor md, SymbolTable nametable,
1472       BlockExpressionNode ben, NodeTupleSet implicitFlowTupleSet) {
1473     analyzeFlowExpressionNode(md, nametable, ben.getExpression(), null, null, implicitFlowTupleSet,
1474         false);
1475   }
1476
1477   private NTuple<Descriptor> analyzeFlowExpressionNode(MethodDescriptor md, SymbolTable nametable,
1478       ExpressionNode en, NodeTupleSet nodeSet, boolean isLHS) {
1479     return analyzeFlowExpressionNode(md, nametable, en, nodeSet, null, new NodeTupleSet(), isLHS);
1480   }
1481
1482   private NTuple<Descriptor> analyzeFlowExpressionNode(MethodDescriptor md, SymbolTable nametable,
1483       ExpressionNode en, NodeTupleSet nodeSet, NTuple<Descriptor> base,
1484       NodeTupleSet implicitFlowTupleSet, boolean isLHS) {
1485
1486     // note that expression node can create more than one flow node
1487     // nodeSet contains of flow nodes
1488     // base is always assigned to null except the case of a name node!
1489
1490     NTuple<Descriptor> flowTuple;
1491
1492     switch (en.kind()) {
1493
1494     case Kind.AssignmentNode:
1495       analyzeFlowAssignmentNode(md, nametable, (AssignmentNode) en, base, implicitFlowTupleSet);
1496       break;
1497
1498     case Kind.FieldAccessNode:
1499       flowTuple =
1500           analyzeFlowFieldAccessNode(md, nametable, (FieldAccessNode) en, nodeSet, base,
1501               implicitFlowTupleSet);
1502       nodeSet.addTuple(flowTuple);
1503       return flowTuple;
1504
1505     case Kind.NameNode:
1506       NodeTupleSet nameNodeSet = new NodeTupleSet();
1507       flowTuple =
1508           analyzeFlowNameNode(md, nametable, (NameNode) en, nameNodeSet, base, implicitFlowTupleSet);
1509       nodeSet.addTuple(flowTuple);
1510       return flowTuple;
1511
1512     case Kind.OpNode:
1513       analyzeFlowOpNode(md, nametable, (OpNode) en, nodeSet, implicitFlowTupleSet);
1514       break;
1515
1516     case Kind.CreateObjectNode:
1517       analyzeCreateObjectNode(md, nametable, (CreateObjectNode) en);
1518       break;
1519
1520     case Kind.ArrayAccessNode:
1521       analyzeFlowArrayAccessNode(md, nametable, (ArrayAccessNode) en, nodeSet, isLHS);
1522       break;
1523
1524     case Kind.LiteralNode:
1525       analyzeLiteralNode(md, nametable, (LiteralNode) en);
1526       break;
1527
1528     case Kind.MethodInvokeNode:
1529       analyzeFlowMethodInvokeNode(md, nametable, (MethodInvokeNode) en, implicitFlowTupleSet);
1530       break;
1531
1532     case Kind.TertiaryNode:
1533       analyzeFlowTertiaryNode(md, nametable, (TertiaryNode) en, nodeSet, implicitFlowTupleSet);
1534       break;
1535
1536     case Kind.CastNode:
1537       analyzeFlowCastNode(md, nametable, (CastNode) en, nodeSet, base, implicitFlowTupleSet);
1538       break;
1539     // case Kind.InstanceOfNode:
1540     // checkInstanceOfNode(md, nametable, (InstanceOfNode) en, td);
1541     // return null;
1542
1543     // case Kind.ArrayInitializerNode:
1544     // checkArrayInitializerNode(md, nametable, (ArrayInitializerNode) en,
1545     // td);
1546     // return null;
1547
1548     // case Kind.ClassTypeNode:
1549     // checkClassTypeNode(md, nametable, (ClassTypeNode) en, td);
1550     // return null;
1551
1552     // case Kind.OffsetNode:
1553     // checkOffsetNode(md, nametable, (OffsetNode)en, td);
1554     // return null;
1555
1556     }
1557     return null;
1558
1559   }
1560
1561   private void analyzeFlowCastNode(MethodDescriptor md, SymbolTable nametable, CastNode cn,
1562       NodeTupleSet nodeSet, NTuple<Descriptor> base, NodeTupleSet implicitFlowTupleSet) {
1563
1564     analyzeFlowExpressionNode(md, nametable, cn.getExpression(), nodeSet, base,
1565         implicitFlowTupleSet, false);
1566
1567   }
1568
1569   private void analyzeFlowTertiaryNode(MethodDescriptor md, SymbolTable nametable, TertiaryNode tn,
1570       NodeTupleSet nodeSet, NodeTupleSet implicitFlowTupleSet) {
1571
1572     NodeTupleSet tertiaryTupleNode = new NodeTupleSet();
1573     analyzeFlowExpressionNode(md, nametable, tn.getCond(), tertiaryTupleNode, null,
1574         implicitFlowTupleSet, false);
1575
1576     // add edges from tertiaryTupleNode to all nodes of conditional nodes
1577     tertiaryTupleNode.addTupleSet(implicitFlowTupleSet);
1578     analyzeFlowExpressionNode(md, nametable, tn.getTrueExpr(), tertiaryTupleNode, null,
1579         implicitFlowTupleSet, false);
1580
1581     analyzeFlowExpressionNode(md, nametable, tn.getFalseExpr(), tertiaryTupleNode, null,
1582         implicitFlowTupleSet, false);
1583
1584     nodeSet.addTupleSet(tertiaryTupleNode);
1585
1586   }
1587
1588   private void addMapCallerMethodDescToMethodInvokeNodeSet(MethodDescriptor caller,
1589       MethodInvokeNode min) {
1590     Set<MethodInvokeNode> set = mapMethodDescriptorToMethodInvokeNodeSet.get(caller);
1591     if (set == null) {
1592       set = new HashSet<MethodInvokeNode>();
1593       mapMethodDescriptorToMethodInvokeNodeSet.put(caller, set);
1594     }
1595     set.add(min);
1596   }
1597
1598   private void analyzeFlowMethodInvokeNode(MethodDescriptor md, SymbolTable nametable,
1599       MethodInvokeNode min, NodeTupleSet implicitFlowTupleSet) {
1600
1601     addMapCallerMethodDescToMethodInvokeNodeSet(md, min);
1602
1603     MethodDescriptor calleeMD = min.getMethod();
1604
1605     NameDescriptor baseName = min.getBaseName();
1606     boolean isSystemout = false;
1607     if (baseName != null) {
1608       isSystemout = baseName.getSymbol().equals("System.out");
1609     }
1610
1611     if (!ssjava.isSSJavaUtil(calleeMD.getClassDesc()) && !ssjava.isTrustMethod(calleeMD)
1612         && !calleeMD.getModifiers().isNative() && !isSystemout) {
1613
1614       // CompositeLocation baseLocation = null;
1615       if (min.getExpression() != null) {
1616
1617         NodeTupleSet baseNodeSet = new NodeTupleSet();
1618         analyzeFlowExpressionNode(md, nametable, min.getExpression(), baseNodeSet, null,
1619             implicitFlowTupleSet, false);
1620
1621       } else {
1622         if (min.getMethod().isStatic()) {
1623           // String globalLocId = ssjava.getMethodLattice(md).getGlobalLoc();
1624           // if (globalLocId == null) {
1625           // throw new
1626           // Error("Method lattice does not define global variable location at "
1627           // + generateErrorMessage(md.getClassDesc(), min));
1628           // }
1629           // baseLocation = new CompositeLocation(new Location(md,
1630           // globalLocId));
1631         } else {
1632           // 'this' var case
1633           // String thisLocId = ssjava.getMethodLattice(md).getThisLoc();
1634           // baseLocation = new CompositeLocation(new Location(md, thisLocId));
1635         }
1636       }
1637
1638       // constraint case:
1639       // if (constraint != null) {
1640       // int compareResult =
1641       // CompositeLattice.compare(constraint, baseLocation, true,
1642       // generateErrorMessage(cd, min));
1643       // if (compareResult != ComparisonResult.GREATER) {
1644       // // if the current constraint is higher than method's THIS location
1645       // // no need to check constraints!
1646       // CompositeLocation calleeConstraint =
1647       // translateCallerLocToCalleeLoc(calleeMD, baseLocation, constraint);
1648       // // System.out.println("check method body for constraint:" + calleeMD +
1649       // // " calleeConstraint="
1650       // // + calleeConstraint);
1651       // checkMethodBody(calleeMD.getClassDesc(), calleeMD, calleeConstraint);
1652       // }
1653       // }
1654
1655       analyzeFlowMethodParameters(md, nametable, min);
1656
1657       // checkCalleeConstraints(md, nametable, min, baseLocation, constraint);
1658
1659       // checkCallerArgumentLocationConstraints(md, nametable, min,
1660       // baseLocation, constraint);
1661
1662       if (min.getMethod().getReturnType() != null && !min.getMethod().getReturnType().isVoid()) {
1663         // If method has a return value, compute the highest possible return
1664         // location in the caller's perspective
1665         // CompositeLocation ceilingLoc =
1666         // computeCeilingLocationForCaller(md, nametable, min, baseLocation,
1667         // constraint);
1668         // return ceilingLoc;
1669       }
1670     }
1671
1672     // return new CompositeLocation(Location.createTopLocation(md));
1673
1674   }
1675
1676   private NTuple<Descriptor> getArgTupleByArgIdx(MethodInvokeNode min, int idx) {
1677     return mapMethodInvokeNodeToArgIdxMap.get(min).get(new Integer(idx));
1678   }
1679
1680   private void addArgIdxMap(MethodInvokeNode min, int idx, NTuple<Descriptor> argTuple) {
1681     Map<Integer, NTuple<Descriptor>> mapIdxToArgTuple = mapMethodInvokeNodeToArgIdxMap.get(min);
1682     if (mapIdxToArgTuple == null) {
1683       mapIdxToArgTuple = new HashMap<Integer, NTuple<Descriptor>>();
1684       mapMethodInvokeNodeToArgIdxMap.put(min, mapIdxToArgTuple);
1685     }
1686     mapIdxToArgTuple.put(new Integer(idx), argTuple);
1687   }
1688
1689   private void analyzeFlowMethodParameters(MethodDescriptor callermd, SymbolTable nametable,
1690       MethodInvokeNode min) {
1691
1692     if (min.numArgs() > 0) {
1693
1694       int offset;
1695       if (min.getMethod().isStatic()) {
1696         offset = 0;
1697       } else {
1698         offset = 1;
1699         NTuple<Descriptor> thisArgTuple = new NTuple<Descriptor>();
1700         thisArgTuple.add(callermd.getThis());
1701         addArgIdxMap(min, 0, thisArgTuple);
1702       }
1703
1704       for (int i = 0; i < min.numArgs(); i++) {
1705         ExpressionNode en = min.getArg(i);
1706         NTuple<Descriptor> argTuple =
1707             analyzeFlowExpressionNode(callermd, nametable, en, new NodeTupleSet(), false);
1708
1709         // if argument is liternal node, argTuple is set to NULL.
1710         addArgIdxMap(min, i + offset, argTuple);
1711       }
1712
1713     }
1714
1715   }
1716
1717   private void analyzeLiteralNode(MethodDescriptor md, SymbolTable nametable, LiteralNode en) {
1718
1719   }
1720
1721   private void analyzeFlowArrayAccessNode(MethodDescriptor md, SymbolTable nametable,
1722       ArrayAccessNode aan, NodeTupleSet nodeSet, boolean isLHS) {
1723
1724     NodeTupleSet expNodeTupleSet = new NodeTupleSet();
1725     analyzeFlowExpressionNode(md, nametable, aan.getExpression(), expNodeTupleSet, isLHS);
1726
1727     NodeTupleSet idxNodeTupleSet = new NodeTupleSet();
1728     analyzeFlowExpressionNode(md, nametable, aan.getIndex(), idxNodeTupleSet, isLHS);
1729
1730     if (isLHS) {
1731       // need to create an edge from idx to array
1732
1733       for (Iterator<NTuple<Descriptor>> idxIter = idxNodeTupleSet.iterator(); idxIter.hasNext();) {
1734         NTuple<Descriptor> idxTuple = idxIter.next();
1735         for (Iterator<NTuple<Descriptor>> arrIter = expNodeTupleSet.iterator(); arrIter.hasNext();) {
1736           NTuple<Descriptor> arrTuple = arrIter.next();
1737           getFlowGraph(md).addValueFlowEdge(idxTuple, arrTuple);
1738         }
1739       }
1740
1741       nodeSet.addTupleSet(expNodeTupleSet);
1742     } else {
1743       nodeSet.addTupleSet(expNodeTupleSet);
1744       nodeSet.addTupleSet(idxNodeTupleSet);
1745     }
1746
1747   }
1748
1749   private void analyzeCreateObjectNode(MethodDescriptor md, SymbolTable nametable,
1750       CreateObjectNode en) {
1751     // TODO Auto-generated method stub
1752
1753   }
1754
1755   private void analyzeFlowOpNode(MethodDescriptor md, SymbolTable nametable, OpNode on,
1756       NodeTupleSet nodeSet, NodeTupleSet implicitFlowTupleSet) {
1757
1758     NodeTupleSet leftOpSet = new NodeTupleSet();
1759     NodeTupleSet rightOpSet = new NodeTupleSet();
1760
1761     // left operand
1762     analyzeFlowExpressionNode(md, nametable, on.getLeft(), leftOpSet, null, implicitFlowTupleSet,
1763         false);
1764
1765     if (on.getRight() != null) {
1766       // right operand
1767       analyzeFlowExpressionNode(md, nametable, on.getRight(), rightOpSet, null,
1768           implicitFlowTupleSet, false);
1769     }
1770
1771     Operation op = on.getOp();
1772
1773     switch (op.getOp()) {
1774
1775     case Operation.UNARYPLUS:
1776     case Operation.UNARYMINUS:
1777     case Operation.LOGIC_NOT:
1778       // single operand
1779       nodeSet.addTupleSet(leftOpSet);
1780       break;
1781
1782     case Operation.LOGIC_OR:
1783     case Operation.LOGIC_AND:
1784     case Operation.COMP:
1785     case Operation.BIT_OR:
1786     case Operation.BIT_XOR:
1787     case Operation.BIT_AND:
1788     case Operation.ISAVAILABLE:
1789     case Operation.EQUAL:
1790     case Operation.NOTEQUAL:
1791     case Operation.LT:
1792     case Operation.GT:
1793     case Operation.LTE:
1794     case Operation.GTE:
1795     case Operation.ADD:
1796     case Operation.SUB:
1797     case Operation.MULT:
1798     case Operation.DIV:
1799     case Operation.MOD:
1800     case Operation.LEFTSHIFT:
1801     case Operation.RIGHTSHIFT:
1802     case Operation.URIGHTSHIFT:
1803
1804       // there are two operands
1805       nodeSet.addTupleSet(leftOpSet);
1806       nodeSet.addTupleSet(rightOpSet);
1807       break;
1808
1809     default:
1810       throw new Error(op.toString());
1811     }
1812
1813   }
1814
1815   private NTuple<Descriptor> analyzeFlowNameNode(MethodDescriptor md, SymbolTable nametable,
1816       NameNode nn, NodeTupleSet nodeSet, NTuple<Descriptor> base, NodeTupleSet implicitFlowTupleSet) {
1817
1818     if (base == null) {
1819       base = new NTuple<Descriptor>();
1820     }
1821
1822     NameDescriptor nd = nn.getName();
1823
1824     if (nd.getBase() != null) {
1825       analyzeFlowExpressionNode(md, nametable, nn.getExpression(), nodeSet, base,
1826           implicitFlowTupleSet, false);
1827     } else {
1828       String varname = nd.toString();
1829       if (varname.equals("this")) {
1830         // 'this' itself!
1831         base.add(md.getThis());
1832         return base;
1833       }
1834
1835       Descriptor d = (Descriptor) nametable.get(varname);
1836
1837       if (d instanceof VarDescriptor) {
1838         VarDescriptor vd = (VarDescriptor) d;
1839         base.add(vd);
1840       } else if (d instanceof FieldDescriptor) {
1841         // the type of field descriptor has a location!
1842         FieldDescriptor fd = (FieldDescriptor) d;
1843         if (fd.isStatic()) {
1844           if (fd.isFinal()) {
1845             // if it is 'static final', assign the default TOP LOCATION
1846             // DESCRIPTOR
1847             base.add(TOPDESC);
1848             return base;
1849           } else {
1850             // if 'static', assign the default GLOBAL LOCATION to the first
1851             // element of the tuple
1852             base.add(GLOBALDESC);
1853           }
1854         } else {
1855           // the location of field access starts from this, followed by field
1856           // location
1857           base.add(md.getThis());
1858         }
1859
1860         base.add(fd);
1861       } else if (d == null) {
1862         // access static field
1863         base.add(GLOBALDESC);
1864         // base.add(nn.getField());
1865         return base;
1866
1867         // FieldDescriptor fd = nn.getField();addFlowGraphEdge
1868         //
1869         // MethodLattice<String> localLattice = ssjava.getMethodLattice(md);
1870         // String globalLocId = localLattice.getGlobalLoc();
1871         // if (globalLocId == null) {
1872         // throw new
1873         // Error("Method lattice does not define global variable location at "
1874         // + generateErrorMessage(md.getClassDesc(), nn));
1875         // }
1876         // loc.addLocation(new Location(md, globalLocId));
1877         //
1878         // Location fieldLoc = (Location) fd.getType().getExtension();
1879         // loc.addLocation(fieldLoc);
1880         //
1881         // return loc;
1882
1883       }
1884     }
1885
1886     getFlowGraph(md).createNewFlowNode(base);
1887
1888     return base;
1889
1890   }
1891
1892   private NTuple<Descriptor> analyzeFlowFieldAccessNode(MethodDescriptor md, SymbolTable nametable,
1893       FieldAccessNode fan, NodeTupleSet nodeSet, NTuple<Descriptor> base,
1894       NodeTupleSet implicitFlowTupleSet) {
1895
1896     ExpressionNode left = fan.getExpression();
1897     TypeDescriptor ltd = left.getType();
1898     FieldDescriptor fd = fan.getField();
1899
1900     String varName = null;
1901     if (left.kind() == Kind.NameNode) {
1902       NameDescriptor nd = ((NameNode) left).getName();
1903       varName = nd.toString();
1904     }
1905
1906     if (ltd.isClassNameRef() || (varName != null && varName.equals("this"))) {
1907       // using a class name directly or access using this
1908       if (fd.isStatic() && fd.isFinal()) {
1909         // loc.addLocation(Location.createTopLocation(md));
1910         // return loc;
1911       }
1912     }
1913
1914     if (left instanceof ArrayAccessNode) {
1915       ArrayAccessNode aan = (ArrayAccessNode) left;
1916       left = aan.getExpression();
1917     }
1918     // fanNodeSet
1919     base =
1920         analyzeFlowExpressionNode(md, nametable, left, nodeSet, base, implicitFlowTupleSet, false);
1921
1922     if (!left.getType().isPrimitive()) {
1923
1924       if (fd.getSymbol().equals("length")) {
1925         // array.length access, just have the location of the array
1926       } else {
1927         base.add(fd);
1928       }
1929
1930     }
1931
1932     getFlowGraph(md).createNewFlowNode(base);
1933     return base;
1934
1935   }
1936
1937   private void debug_printTreeNode(TreeNode tn) {
1938
1939     System.out.println("DEBUG: " + tn.printNode(0) + "                line#=" + tn.getNumLine());
1940
1941   }
1942
1943   private void analyzeFlowAssignmentNode(MethodDescriptor md, SymbolTable nametable,
1944       AssignmentNode an, NTuple<Descriptor> base, NodeTupleSet implicitFlowTupleSet) {
1945
1946     NodeTupleSet nodeSetRHS = new NodeTupleSet();
1947     NodeTupleSet nodeSetLHS = new NodeTupleSet();
1948
1949     boolean postinc = true;
1950     if (an.getOperation().getBaseOp() == null
1951         || (an.getOperation().getBaseOp().getOp() != Operation.POSTINC && an.getOperation()
1952             .getBaseOp().getOp() != Operation.POSTDEC)) {
1953       postinc = false;
1954     }
1955     // if LHS is array access node, need to capture value flows between an array
1956     // and its index value
1957     analyzeFlowExpressionNode(md, nametable, an.getDest(), nodeSetLHS, null, implicitFlowTupleSet,
1958         true);
1959
1960     if (!postinc) {
1961       // analyze value flows of rhs expression
1962       analyzeFlowExpressionNode(md, nametable, an.getSrc(), nodeSetRHS, null, implicitFlowTupleSet,
1963           false);
1964
1965       if (an.getOperation().getOp() >= 2 && an.getOperation().getOp() <= 12) {
1966         // if assignment contains OP+EQ operator, creates edges from LHS to LHS
1967         for (Iterator<NTuple<Descriptor>> iter = nodeSetLHS.iterator(); iter.hasNext();) {
1968           NTuple<Descriptor> fromTuple = iter.next();
1969           for (Iterator<NTuple<Descriptor>> iter2 = nodeSetLHS.iterator(); iter2.hasNext();) {
1970             NTuple<Descriptor> toTuple = iter2.next();
1971             addFlowGraphEdge(md, fromTuple, toTuple);
1972           }
1973         }
1974       }
1975
1976       // creates edges from RHS to LHS
1977       for (Iterator<NTuple<Descriptor>> iter = nodeSetRHS.iterator(); iter.hasNext();) {
1978         NTuple<Descriptor> fromTuple = iter.next();
1979         for (Iterator<NTuple<Descriptor>> iter2 = nodeSetLHS.iterator(); iter2.hasNext();) {
1980           NTuple<Descriptor> toTuple = iter2.next();
1981           addFlowGraphEdge(md, fromTuple, toTuple);
1982         }
1983       }
1984
1985       // creates edges from implicitFlowTupleSet to LHS
1986       for (Iterator<NTuple<Descriptor>> iter = implicitFlowTupleSet.iterator(); iter.hasNext();) {
1987         NTuple<Descriptor> fromTuple = iter.next();
1988         for (Iterator<NTuple<Descriptor>> iter2 = nodeSetLHS.iterator(); iter2.hasNext();) {
1989           NTuple<Descriptor> toTuple = iter2.next();
1990           addFlowGraphEdge(md, fromTuple, toTuple);
1991         }
1992       }
1993
1994     } else {
1995       // postinc case
1996       for (Iterator<NTuple<Descriptor>> iter2 = nodeSetLHS.iterator(); iter2.hasNext();) {
1997         NTuple<Descriptor> tuple = iter2.next();
1998         addFlowGraphEdge(md, tuple, tuple);
1999       }
2000
2001     }
2002
2003   }
2004
2005   public FlowGraph getFlowGraph(MethodDescriptor md) {
2006     return mapMethodDescriptorToFlowGraph.get(md);
2007   }
2008
2009   private boolean addFlowGraphEdge(MethodDescriptor md, NTuple<Descriptor> from,
2010       NTuple<Descriptor> to) {
2011     // TODO
2012     // return true if it adds a new edge
2013     FlowGraph graph = getFlowGraph(md);
2014     graph.addValueFlowEdge(from, to);
2015     return true;
2016   }
2017
2018   public void _debug_printGraph() {
2019     Set<MethodDescriptor> keySet = mapMethodDescriptorToFlowGraph.keySet();
2020
2021     for (Iterator<MethodDescriptor> iterator = keySet.iterator(); iterator.hasNext();) {
2022       MethodDescriptor md = (MethodDescriptor) iterator.next();
2023       FlowGraph fg = mapMethodDescriptorToFlowGraph.get(md);
2024       try {
2025         fg.writeGraph();
2026       } catch (IOException e) {
2027         e.printStackTrace();
2028       }
2029     }
2030
2031   }
2032
2033 }