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