6404a8f9984fdc520736c8a12d0ebf077898cf04
[IRC.git] / Robust / src / Analysis / SSJava / LocationInference.java
1 package Analysis.SSJava;
2
3 import java.io.BufferedReader;
4 import java.io.BufferedWriter;
5 import java.io.FileReader;
6 import java.io.FileWriter;
7 import java.io.IOException;
8 import java.util.ArrayList;
9 import java.util.Collections;
10 import java.util.Comparator;
11 import java.util.HashMap;
12 import java.util.HashSet;
13 import java.util.Iterator;
14 import java.util.LinkedList;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Set;
18 import java.util.Stack;
19 import java.util.Vector;
20
21 import IR.ClassDescriptor;
22 import IR.Descriptor;
23 import IR.FieldDescriptor;
24 import IR.MethodDescriptor;
25 import IR.NameDescriptor;
26 import IR.Operation;
27 import IR.State;
28 import IR.SymbolTable;
29 import IR.TypeDescriptor;
30 import IR.VarDescriptor;
31 import IR.Tree.ArrayAccessNode;
32 import IR.Tree.AssignmentNode;
33 import IR.Tree.BlockExpressionNode;
34 import IR.Tree.BlockNode;
35 import IR.Tree.BlockStatementNode;
36 import IR.Tree.CastNode;
37 import IR.Tree.CreateObjectNode;
38 import IR.Tree.DeclarationNode;
39 import IR.Tree.ExpressionNode;
40 import IR.Tree.FieldAccessNode;
41 import IR.Tree.IfStatementNode;
42 import IR.Tree.Kind;
43 import IR.Tree.LiteralNode;
44 import IR.Tree.LoopNode;
45 import IR.Tree.MethodInvokeNode;
46 import IR.Tree.NameNode;
47 import IR.Tree.OpNode;
48 import IR.Tree.ReturnNode;
49 import IR.Tree.SubBlockNode;
50 import IR.Tree.SwitchStatementNode;
51 import IR.Tree.TertiaryNode;
52 import IR.Tree.TreeNode;
53 import Util.Pair;
54
55 public class LocationInference {
56
57   State state;
58   SSJavaAnalysis ssjava;
59
60   List<ClassDescriptor> toanalyzeList;
61   List<MethodDescriptor> toanalyzeMethodList;
62   Map<MethodDescriptor, FlowGraph> mapMethodDescriptorToFlowGraph;
63
64   // map a method descriptor to its set of parameter descriptors
65   Map<MethodDescriptor, Set<Descriptor>> mapMethodDescriptorToParamDescSet;
66
67   // keep current descriptors to visit in fixed-point interprocedural analysis,
68   private Stack<MethodDescriptor> methodDescriptorsToVisitStack;
69
70   // map a class descriptor to a field lattice
71   private Map<ClassDescriptor, SSJavaLattice<String>> cd2lattice;
72
73   // map a method descriptor to a method lattice
74   private Map<MethodDescriptor, SSJavaLattice<String>> md2lattice;
75
76   // map a method descriptor to the set of method invocation nodes which are
77   // invoked by the method descriptor
78   private Map<MethodDescriptor, Set<MethodInvokeNode>> mapMethodDescriptorToMethodInvokeNodeSet;
79
80   private Map<MethodInvokeNode, Map<Integer, NodeTupleSet>> mapMethodInvokeNodeToArgIdxMap;
81
82   private Map<MethodDescriptor, MethodLocationInfo> mapMethodDescToMethodLocationInfo;
83
84   private Map<ClassDescriptor, LocationInfo> mapClassToLocationInfo;
85
86   private Map<MethodDescriptor, Set<MethodDescriptor>> mapMethodToCalleeSet;
87
88   private Map<String, Vector<String>> mapFileNameToLineVector;
89
90   private Map<Descriptor, Integer> mapDescToDefinitionLine;
91
92   public static final String GLOBALLOC = "GLOBALLOC";
93
94   public static final String TOPLOC = "TOPLOC";
95
96   public static final Descriptor GLOBALDESC = new NameDescriptor(GLOBALLOC);
97
98   public static final Descriptor TOPDESC = new NameDescriptor(TOPLOC);
99
100   public static String newline = System.getProperty("line.separator");
101
102   LocationInfo curMethodInfo;
103
104   boolean debug = true;
105
106   public LocationInference(SSJavaAnalysis ssjava, State state) {
107     this.ssjava = ssjava;
108     this.state = state;
109     this.toanalyzeList = new ArrayList<ClassDescriptor>();
110     this.toanalyzeMethodList = new ArrayList<MethodDescriptor>();
111     this.mapMethodDescriptorToFlowGraph = new HashMap<MethodDescriptor, FlowGraph>();
112     this.cd2lattice = new HashMap<ClassDescriptor, SSJavaLattice<String>>();
113     this.md2lattice = new HashMap<MethodDescriptor, SSJavaLattice<String>>();
114     this.methodDescriptorsToVisitStack = new Stack<MethodDescriptor>();
115     this.mapMethodDescriptorToMethodInvokeNodeSet =
116         new HashMap<MethodDescriptor, Set<MethodInvokeNode>>();
117     this.mapMethodInvokeNodeToArgIdxMap =
118         new HashMap<MethodInvokeNode, Map<Integer, NodeTupleSet>>();
119     this.mapMethodDescToMethodLocationInfo = new HashMap<MethodDescriptor, MethodLocationInfo>();
120     this.mapMethodToCalleeSet = new HashMap<MethodDescriptor, Set<MethodDescriptor>>();
121     this.mapClassToLocationInfo = new HashMap<ClassDescriptor, LocationInfo>();
122
123     this.mapFileNameToLineVector = new HashMap<String, Vector<String>>();
124     this.mapDescToDefinitionLine = new HashMap<Descriptor, Integer>();
125   }
126
127   public void setupToAnalyze() {
128     SymbolTable classtable = state.getClassSymbolTable();
129     toanalyzeList.clear();
130     toanalyzeList.addAll(classtable.getValueSet());
131     Collections.sort(toanalyzeList, new Comparator<ClassDescriptor>() {
132       public int compare(ClassDescriptor o1, ClassDescriptor o2) {
133         return o1.getClassName().compareToIgnoreCase(o2.getClassName());
134       }
135     });
136   }
137
138   public void setupToAnalazeMethod(ClassDescriptor cd) {
139
140     SymbolTable methodtable = cd.getMethodTable();
141     toanalyzeMethodList.clear();
142     toanalyzeMethodList.addAll(methodtable.getValueSet());
143     Collections.sort(toanalyzeMethodList, new Comparator<MethodDescriptor>() {
144       public int compare(MethodDescriptor o1, MethodDescriptor o2) {
145         return o1.getSymbol().compareToIgnoreCase(o2.getSymbol());
146       }
147     });
148   }
149
150   public boolean toAnalyzeMethodIsEmpty() {
151     return toanalyzeMethodList.isEmpty();
152   }
153
154   public boolean toAnalyzeIsEmpty() {
155     return toanalyzeList.isEmpty();
156   }
157
158   public ClassDescriptor toAnalyzeNext() {
159     return toanalyzeList.remove(0);
160   }
161
162   public MethodDescriptor toAnalyzeMethodNext() {
163     return toanalyzeMethodList.remove(0);
164   }
165
166   public void inference() {
167
168     // 1) construct value flow graph
169     constructFlowGraph();
170
171     // 2) construct lattices
172     inferLattices();
173
174     simplifyLattices();
175
176     debug_writeLatticeDotFile();
177
178     // 3) check properties
179     checkLattices();
180
181     // 4) generate annotated source codes
182     generateAnnoatedCode();
183
184   }
185
186   private void addMapClassDefinitionToLineNum(ClassDescriptor cd, String strLine, int lineNum) {
187
188     String classSymbol = cd.getSymbol();
189     int idx = classSymbol.lastIndexOf("$");
190     if (idx != -1) {
191       classSymbol = classSymbol.substring(idx + 1);
192     }
193
194     String pattern = "class " + classSymbol + " ";
195     if (strLine.indexOf(pattern) != -1) {
196       mapDescToDefinitionLine.put(cd, lineNum);
197     }
198   }
199
200   private void addMapMethodDefinitionToLineNum(Set<MethodDescriptor> methodSet, String strLine,
201       int lineNum) {
202     for (Iterator iterator = methodSet.iterator(); iterator.hasNext();) {
203       MethodDescriptor md = (MethodDescriptor) iterator.next();
204       String pattern = md.getMethodDeclaration();
205       if (strLine.indexOf(pattern) != -1) {
206         mapDescToDefinitionLine.put(md, lineNum);
207         methodSet.remove(md);
208         return;
209       }
210     }
211
212   }
213
214   private void readOriginalSourceFiles() {
215
216     SymbolTable classtable = state.getClassSymbolTable();
217
218     Set<ClassDescriptor> classDescSet = new HashSet<ClassDescriptor>();
219     classDescSet.addAll(classtable.getValueSet());
220
221     try {
222       // inefficient implement. it may re-visit the same file if the file
223       // contains more than one class definitions.
224       for (Iterator iterator = classDescSet.iterator(); iterator.hasNext();) {
225         ClassDescriptor cd = (ClassDescriptor) iterator.next();
226
227         Set<MethodDescriptor> methodSet = new HashSet<MethodDescriptor>();
228         methodSet.addAll(cd.getMethodTable().getValueSet());
229
230         String sourceFileName = cd.getSourceFileName();
231         Vector<String> lineVec = new Vector<String>();
232
233         mapFileNameToLineVector.put(sourceFileName, lineVec);
234
235         BufferedReader in = new BufferedReader(new FileReader(sourceFileName));
236         String strLine;
237         int lineNum = 1;
238         lineVec.add(""); // the index is started from 1.
239         while ((strLine = in.readLine()) != null) {
240           lineVec.add(lineNum, strLine);
241           addMapClassDefinitionToLineNum(cd, strLine, lineNum);
242           addMapMethodDefinitionToLineNum(methodSet, strLine, lineNum);
243           lineNum++;
244         }
245
246       }
247
248     } catch (IOException e) {
249       e.printStackTrace();
250     }
251
252   }
253
254   private String generateLatticeDefinition(Descriptor desc) {
255
256     Set<String> sharedLocSet = new HashSet<String>();
257
258     SSJavaLattice<String> lattice = getLattice(desc);
259     String rtr = "@LATTICE(\"";
260
261     Map<String, Set<String>> map = lattice.getTable();
262     Set<String> keySet = map.keySet();
263     boolean first = true;
264     for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
265       String key = (String) iterator.next();
266       if (!key.equals(lattice.getTopItem())) {
267         Set<String> connectedSet = map.get(key);
268
269         if (connectedSet.size() == 1) {
270           if (connectedSet.iterator().next().equals(lattice.getBottomItem())) {
271             if (!first) {
272               rtr += ",";
273             } else {
274               rtr += "LOC,";
275               first = false;
276             }
277             rtr += key;
278             if (lattice.isSharedLoc(key)) {
279               rtr += "," + key + "*";
280             }
281           }
282         }
283
284         for (Iterator iterator2 = connectedSet.iterator(); iterator2.hasNext();) {
285           String loc = (String) iterator2.next();
286           if (!loc.equals(lattice.getBottomItem())) {
287             if (!first) {
288               rtr += ",";
289             } else {
290               rtr += "LOC,";
291               first = false;
292             }
293             rtr += loc + "<" + key;
294             if (lattice.isSharedLoc(key) && (!sharedLocSet.contains(key))) {
295               rtr += "," + key + "*";
296               sharedLocSet.add(key);
297             }
298             if (lattice.isSharedLoc(loc) && (!sharedLocSet.contains(loc))) {
299               rtr += "," + loc + "*";
300               sharedLocSet.add(loc);
301             }
302
303           }
304         }
305       }
306     }
307
308     rtr += "\")";
309
310     if (desc instanceof MethodDescriptor) {
311       TypeDescriptor returnType = ((MethodDescriptor) desc).getReturnType();
312       if (returnType != null && (!returnType.isVoid())) {
313         rtr += "\n@RETURNLOC(\"RETURNLOC\")";
314       }
315       rtr += "\n@THISLOC(\"this\")\n@PCLOC(\"PCLOC\")\n@GLOBALLOC(\"GLOBALLOC\")";
316
317     }
318
319     return rtr;
320   }
321
322   private void generateAnnoatedCode() {
323
324     readOriginalSourceFiles();
325
326     setupToAnalyze();
327     while (!toAnalyzeIsEmpty()) {
328       ClassDescriptor cd = toAnalyzeNext();
329
330       setupToAnalazeMethod(cd);
331
332       LocationInfo locInfo = mapClassToLocationInfo.get(cd);
333       String sourceFileName = cd.getSourceFileName();
334
335       if (cd.isInterface()) {
336         continue;
337       }
338
339       int classDefLine = mapDescToDefinitionLine.get(cd);
340       Vector<String> sourceVec = mapFileNameToLineVector.get(sourceFileName);
341
342       if (locInfo == null) {
343         locInfo = getLocationInfo(cd);
344       }
345
346       for (Iterator iter = cd.getFields(); iter.hasNext();) {
347         Descriptor fieldDesc = (Descriptor) iter.next();
348         String locIdentifier = locInfo.getFieldInferLocation(fieldDesc).getLocIdentifier();
349         if (!getLattice(cd).containsKey(locIdentifier)) {
350           getLattice(cd).put(locIdentifier);
351         }
352       }
353
354       String fieldLatticeDefStr = generateLatticeDefinition(cd);
355       String annoatedSrc = fieldLatticeDefStr + newline + sourceVec.get(classDefLine);
356       sourceVec.set(classDefLine, annoatedSrc);
357
358       // generate annotations for field declarations
359       LocationInfo fieldLocInfo = getLocationInfo(cd);
360       Map<Descriptor, CompositeLocation> inferLocMap = fieldLocInfo.getMapDescToInferLocation();
361
362       for (Iterator iter = cd.getFields(); iter.hasNext();) {
363         FieldDescriptor fd = (FieldDescriptor) iter.next();
364
365         String locAnnotationStr;
366         if (inferLocMap.containsKey(fd)) {
367           CompositeLocation inferLoc = inferLocMap.get(fd);
368           locAnnotationStr = generateLocationAnnoatation(inferLoc);
369         } else {
370           // if the field is not accssed by SS part, just assigns dummy
371           // location
372           locAnnotationStr = "@LOC(\"LOC\")";
373         }
374         int fdLineNum = fd.getLineNum();
375         String orgFieldDeclarationStr = sourceVec.get(fdLineNum);
376         String fieldDeclaration = fd.toString();
377         fieldDeclaration = fieldDeclaration.substring(0, fieldDeclaration.length() - 1);
378
379         String annoatedStr = locAnnotationStr + " " + orgFieldDeclarationStr;
380         sourceVec.set(fdLineNum, annoatedStr);
381
382       }
383
384       while (!toAnalyzeMethodIsEmpty()) {
385         MethodDescriptor md = toAnalyzeMethodNext();
386         SSJavaLattice<String> methodLattice = md2lattice.get(md);
387         if (methodLattice != null) {
388
389           int methodDefLine = md.getLineNum();
390
391           MethodLocationInfo methodLocInfo = getMethodLocationInfo(md);
392
393           Map<Descriptor, CompositeLocation> methodInferLocMap =
394               methodLocInfo.getMapDescToInferLocation();
395           Set<Descriptor> localVarDescSet = methodInferLocMap.keySet();
396
397           for (Iterator iterator = localVarDescSet.iterator(); iterator.hasNext();) {
398             Descriptor localVarDesc = (Descriptor) iterator.next();
399             CompositeLocation inferLoc = methodInferLocMap.get(localVarDesc);
400
401             String locAnnotationStr = generateLocationAnnoatation(inferLoc);
402
403             if (!isParameter(md, localVarDesc)) {
404               if (mapDescToDefinitionLine.containsKey(localVarDesc)) {
405                 int varLineNum = mapDescToDefinitionLine.get(localVarDesc);
406                 String orgSourceLine = sourceVec.get(varLineNum);
407                 int idx =
408                     orgSourceLine.indexOf(generateVarDeclaration((VarDescriptor) localVarDesc));
409                 assert (idx != -1);
410                 String annoatedStr =
411                     orgSourceLine.substring(0, idx) + locAnnotationStr + " "
412                         + orgSourceLine.substring(idx);
413                 sourceVec.set(varLineNum, annoatedStr);
414               }
415             } else {
416               String methodDefStr = sourceVec.get(methodDefLine);
417               int idx = methodDefStr.indexOf(generateVarDeclaration((VarDescriptor) localVarDesc));
418               assert (idx != -1);
419               String annoatedStr =
420                   methodDefStr.substring(0, idx) + locAnnotationStr + " "
421                       + methodDefStr.substring(idx);
422               sourceVec.set(methodDefLine, annoatedStr);
423             }
424
425           }
426
427           String methodLatticeDefStr = generateLatticeDefinition(md);
428           String annoatedStr = methodLatticeDefStr + newline + sourceVec.get(methodDefLine);
429           sourceVec.set(methodDefLine, annoatedStr);
430
431         }
432       }
433
434     }
435
436     codeGen();
437   }
438
439   private String generateVarDeclaration(VarDescriptor varDesc) {
440
441     TypeDescriptor td = varDesc.getType();
442     String rtr = td.toString();
443     if (td.isArray()) {
444       for (int i = 0; i < td.getArrayCount(); i++) {
445         rtr += "[]";
446       }
447     }
448     rtr += " " + varDesc.getName();
449     return rtr;
450
451   }
452
453   private String generateLocationAnnoatation(CompositeLocation loc) {
454     String rtr = "@LOC(\"";
455
456     // method location
457     Location methodLoc = loc.get(0);
458     rtr += methodLoc.getLocIdentifier();
459
460     for (int i = 1; i < loc.getSize(); i++) {
461       Location element = loc.get(i);
462       rtr += "," + element.getDescriptor().getSymbol() + "." + element.getLocIdentifier();
463     }
464
465     rtr += "\")";
466     return rtr;
467   }
468
469   private boolean isParameter(MethodDescriptor md, Descriptor localVarDesc) {
470     return getFlowGraph(md).isParamDesc(localVarDesc);
471   }
472
473   private String extractFileName(String fileName) {
474     int idx = fileName.lastIndexOf("/");
475     if (idx == -1) {
476       return fileName;
477     } else {
478       return fileName.substring(idx + 1);
479     }
480
481   }
482
483   private void codeGen() {
484
485     Set<String> originalFileNameSet = mapFileNameToLineVector.keySet();
486     for (Iterator iterator = originalFileNameSet.iterator(); iterator.hasNext();) {
487       String orgFileName = (String) iterator.next();
488       String outputFileName = extractFileName(orgFileName);
489
490       Vector<String> sourceVec = mapFileNameToLineVector.get(orgFileName);
491
492       try {
493
494         FileWriter fileWriter = new FileWriter("./infer/" + outputFileName);
495         BufferedWriter out = new BufferedWriter(fileWriter);
496
497         for (int i = 0; i < sourceVec.size(); i++) {
498           out.write(sourceVec.get(i));
499           out.newLine();
500         }
501         out.close();
502       } catch (IOException e) {
503         e.printStackTrace();
504       }
505
506     }
507
508   }
509
510   private void simplifyLattices() {
511
512     // generate lattice dot file
513     setupToAnalyze();
514
515     while (!toAnalyzeIsEmpty()) {
516       ClassDescriptor cd = toAnalyzeNext();
517
518       setupToAnalazeMethod(cd);
519
520       SSJavaLattice<String> classLattice = cd2lattice.get(cd);
521       if (classLattice != null) {
522         classLattice.removeRedundantEdges();
523       }
524
525       while (!toAnalyzeMethodIsEmpty()) {
526         MethodDescriptor md = toAnalyzeMethodNext();
527         SSJavaLattice<String> methodLattice = md2lattice.get(md);
528         if (methodLattice != null) {
529           methodLattice.removeRedundantEdges();
530         }
531       }
532     }
533
534   }
535
536   private void checkLattices() {
537
538     LinkedList<MethodDescriptor> descriptorListToAnalyze = ssjava.getSortedDescriptors();
539
540     // current descriptors to visit in fixed-point interprocedural analysis,
541     // prioritized by
542     // dependency in the call graph
543     methodDescriptorsToVisitStack.clear();
544
545     descriptorListToAnalyze.removeFirst();
546
547     Set<MethodDescriptor> methodDescriptorToVistSet = new HashSet<MethodDescriptor>();
548     methodDescriptorToVistSet.addAll(descriptorListToAnalyze);
549
550     while (!descriptorListToAnalyze.isEmpty()) {
551       MethodDescriptor md = descriptorListToAnalyze.removeFirst();
552       checkLatticesOfVirtualMethods(md);
553     }
554
555   }
556
557   private void debug_writeLatticeDotFile() {
558     // generate lattice dot file
559
560     setupToAnalyze();
561
562     while (!toAnalyzeIsEmpty()) {
563       ClassDescriptor cd = toAnalyzeNext();
564
565       setupToAnalazeMethod(cd);
566
567       SSJavaLattice<String> classLattice = cd2lattice.get(cd);
568       if (classLattice != null) {
569         ssjava.writeLatticeDotFile(cd, null, classLattice);
570         debug_printDescriptorToLocNameMapping(cd);
571       }
572
573       while (!toAnalyzeMethodIsEmpty()) {
574         MethodDescriptor md = toAnalyzeMethodNext();
575         SSJavaLattice<String> methodLattice = md2lattice.get(md);
576         if (methodLattice != null) {
577           ssjava.writeLatticeDotFile(cd, md, methodLattice);
578           debug_printDescriptorToLocNameMapping(md);
579         }
580       }
581     }
582
583   }
584
585   private void debug_printDescriptorToLocNameMapping(Descriptor desc) {
586
587     LocationInfo info = getLocationInfo(desc);
588     System.out.println("## " + desc + " ##");
589     System.out.println(info.getMapDescToInferLocation());
590     LocationInfo locInfo = getLocationInfo(desc);
591     System.out.println("mapping=" + locInfo.getMapLocSymbolToDescSet());
592     System.out.println("###################");
593
594   }
595
596   private void inferLattices() {
597
598     // do fixed-point analysis
599
600     LinkedList<MethodDescriptor> descriptorListToAnalyze = ssjava.getSortedDescriptors();
601
602     Collections.sort(descriptorListToAnalyze, new Comparator<MethodDescriptor>() {
603       public int compare(MethodDescriptor o1, MethodDescriptor o2) {
604         return o1.getSymbol().compareToIgnoreCase(o2.getSymbol());
605       }
606     });
607
608     // current descriptors to visit in fixed-point interprocedural analysis,
609     // prioritized by
610     // dependency in the call graph
611     methodDescriptorsToVisitStack.clear();
612
613     // descriptorListToAnalyze.removeFirst();
614
615     Set<MethodDescriptor> methodDescriptorToVistSet = new HashSet<MethodDescriptor>();
616     methodDescriptorToVistSet.addAll(descriptorListToAnalyze);
617
618     while (!descriptorListToAnalyze.isEmpty()) {
619       MethodDescriptor md = descriptorListToAnalyze.removeFirst();
620       methodDescriptorsToVisitStack.add(md);
621     }
622
623     // analyze scheduled methods until there are no more to visit
624     while (!methodDescriptorsToVisitStack.isEmpty()) {
625       // start to analyze leaf node
626       MethodDescriptor md = methodDescriptorsToVisitStack.pop();
627
628       SSJavaLattice<String> methodLattice =
629           new SSJavaLattice<String>(SSJavaAnalysis.TOP, SSJavaAnalysis.BOTTOM);
630
631       MethodLocationInfo methodInfo = new MethodLocationInfo(md);
632       curMethodInfo = methodInfo;
633
634       System.out.println();
635       System.out.println("SSJAVA: Inferencing the lattice from " + md);
636
637       try {
638         analyzeMethodLattice(md, methodLattice, methodInfo);
639       } catch (CyclicFlowException e) {
640         throw new Error("Fail to generate the method lattice for " + md);
641       }
642
643       SSJavaLattice<String> prevMethodLattice = getMethodLattice(md);
644       MethodLocationInfo prevMethodInfo = getMethodLocationInfo(md);
645
646       if ((!methodLattice.equals(prevMethodLattice)) || (!methodInfo.equals(prevMethodInfo))) {
647
648         setMethodLattice(md, methodLattice);
649         setMethodLocInfo(md, methodInfo);
650
651         // results for callee changed, so enqueue dependents caller for
652         // further analysis
653         Iterator<MethodDescriptor> depsItr = ssjava.getDependents(md).iterator();
654         while (depsItr.hasNext()) {
655           MethodDescriptor methodNext = depsItr.next();
656           if (!methodDescriptorsToVisitStack.contains(methodNext)
657               && methodDescriptorToVistSet.contains(methodNext)) {
658             methodDescriptorsToVisitStack.add(methodNext);
659           }
660         }
661
662       }
663
664     }
665   }
666
667   private void setMethodLocInfo(MethodDescriptor md, MethodLocationInfo methodInfo) {
668     mapMethodDescToMethodLocationInfo.put(md, methodInfo);
669   }
670
671   private void checkLatticesOfVirtualMethods(MethodDescriptor md) {
672
673     if (!md.isStatic()) {
674       Set<MethodDescriptor> setPossibleCallees = new HashSet<MethodDescriptor>();
675       setPossibleCallees.addAll(ssjava.getCallGraph().getMethods(md));
676
677       for (Iterator iterator = setPossibleCallees.iterator(); iterator.hasNext();) {
678         MethodDescriptor mdCallee = (MethodDescriptor) iterator.next();
679         if (!md.equals(mdCallee)) {
680           checkConsistency(md, mdCallee);
681         }
682       }
683
684     }
685
686   }
687
688   private void checkConsistency(MethodDescriptor md1, MethodDescriptor md2) {
689
690     // check that two lattice have the same relations between parameters(+PC
691     // LOC, GLOBAL_LOC RETURN LOC)
692
693     List<CompositeLocation> list1 = new ArrayList<CompositeLocation>();
694     List<CompositeLocation> list2 = new ArrayList<CompositeLocation>();
695
696     MethodLocationInfo locInfo1 = getMethodLocationInfo(md1);
697     MethodLocationInfo locInfo2 = getMethodLocationInfo(md2);
698
699     Map<Integer, CompositeLocation> paramMap1 = locInfo1.getMapParamIdxToInferLoc();
700     Map<Integer, CompositeLocation> paramMap2 = locInfo2.getMapParamIdxToInferLoc();
701
702     int numParam = locInfo1.getMapParamIdxToInferLoc().keySet().size();
703
704     // add location types of paramters
705     for (int idx = 0; idx < numParam; idx++) {
706       list1.add(paramMap1.get(Integer.valueOf(idx)));
707       list2.add(paramMap2.get(Integer.valueOf(idx)));
708     }
709
710     // add program counter location
711     list1.add(locInfo1.getPCLoc());
712     list2.add(locInfo2.getPCLoc());
713
714     if (!md1.getReturnType().isVoid()) {
715       // add return value location
716       CompositeLocation rtrLoc1 =
717           new CompositeLocation(new Location(md1, locInfo1.getReturnLocName()));
718       CompositeLocation rtrLoc2 =
719           new CompositeLocation(new Location(md2, locInfo2.getReturnLocName()));
720       list1.add(rtrLoc1);
721       list2.add(rtrLoc2);
722     }
723
724     // add global location type
725     if (md1.isStatic()) {
726       CompositeLocation globalLoc1 =
727           new CompositeLocation(new Location(md1, locInfo1.getGlobalLocName()));
728       CompositeLocation globalLoc2 =
729           new CompositeLocation(new Location(md2, locInfo2.getGlobalLocName()));
730       list1.add(globalLoc1);
731       list2.add(globalLoc2);
732     }
733
734     for (int i = 0; i < list1.size(); i++) {
735       CompositeLocation locA1 = list1.get(i);
736       CompositeLocation locA2 = list2.get(i);
737       for (int k = 0; k < list1.size(); k++) {
738         if (i != k) {
739           CompositeLocation locB1 = list1.get(k);
740           CompositeLocation locB2 = list2.get(k);
741           boolean r1 = isGreaterThan(getLattice(md1), locA1, locB1);
742
743           boolean r2 = isGreaterThan(getLattice(md1), locA2, locB2);
744
745           if (r1 != r2) {
746             throw new Error("The method " + md1 + " is not consistent with the method " + md2
747                 + ".:: They have a different ordering relation between locations (" + locA1 + ","
748                 + locB1 + ") and (" + locA2 + "," + locB2 + ").");
749           }
750         }
751       }
752     }
753
754   }
755
756   private String getSymbol(int idx, FlowNode node) {
757     Descriptor desc = node.getDescTuple().get(idx);
758     return desc.getSymbol();
759   }
760
761   private Descriptor getDescriptor(int idx, FlowNode node) {
762     Descriptor desc = node.getDescTuple().get(idx);
763     return desc;
764   }
765
766   private void analyzeMethodLattice(MethodDescriptor md, SSJavaLattice<String> methodLattice,
767       MethodLocationInfo methodInfo) throws CyclicFlowException {
768
769     // first take a look at method invocation nodes to newly added relations
770     // from the callee
771     analyzeLatticeMethodInvocationNode(md, methodLattice, methodInfo);
772
773     if (!md.isStatic()) {
774       // set the this location
775       String thisLocSymbol = md.getThis().getSymbol();
776       methodInfo.setThisLocName(thisLocSymbol);
777     }
778
779     // set the global location
780     methodInfo.setGlobalLocName(LocationInference.GLOBALLOC);
781     methodInfo.mapDescriptorToLocation(GLOBALDESC, new CompositeLocation(
782         new Location(md, GLOBALLOC)));
783
784     // visit each node of method flow graph
785     FlowGraph fg = getFlowGraph(md);
786     Set<FlowNode> nodeSet = fg.getNodeSet();
787
788     // for the method lattice, we need to look at the first element of
789     // NTuple<Descriptor>
790     for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
791       FlowNode srcNode = (FlowNode) iterator.next();
792
793       Set<FlowEdge> outEdgeSet = srcNode.getOutEdgeSet();
794       for (Iterator iterator2 = outEdgeSet.iterator(); iterator2.hasNext();) {
795         FlowEdge outEdge = (FlowEdge) iterator2.next();
796         FlowNode dstNode = outEdge.getDst();
797
798         NTuple<Descriptor> srcNodeTuple = srcNode.getDescTuple();
799         NTuple<Descriptor> dstNodeTuple = dstNode.getDescTuple();
800
801         if (outEdge.getInitTuple().equals(srcNodeTuple)
802             && outEdge.getEndTuple().equals(dstNodeTuple)) {
803
804           if ((srcNodeTuple.size() > 1 && dstNodeTuple.size() > 1)
805               && srcNodeTuple.get(0).equals(dstNodeTuple.get(0))) {
806
807             // value flows between fields
808             Descriptor desc = srcNodeTuple.get(0);
809             ClassDescriptor classDesc;
810
811             if (desc.equals(GLOBALDESC)) {
812               classDesc = md.getClassDesc();
813             } else {
814               VarDescriptor varDesc = (VarDescriptor) srcNodeTuple.get(0);
815               classDesc = varDesc.getType().getClassDesc();
816             }
817             extractRelationFromFieldFlows(classDesc, srcNode, dstNode, 1);
818
819           } else {
820             // value flow between local var - local var or local var - field
821             addRelationToLattice(md, methodLattice, methodInfo, srcNode, dstNode);
822           }
823
824           // else if (srcNodeTuple.size() == 1 || dstNodeTuple.size() == 1) {
825           // // for the method lattice, we need to look at the first element of
826           // // NTuple<Descriptor>
827           // // in this case, take a look at connected nodes at the local level
828           // addRelationToLattice(md, methodLattice, methodInfo, srcNode,
829           // dstNode);
830           // } else {
831           // if
832           // (!srcNode.getDescTuple().get(0).equals(dstNode.getDescTuple().get(0)))
833           // {
834           // // in this case, take a look at connected nodes at the local level
835           // addRelationToLattice(md, methodLattice, methodInfo, srcNode,
836           // dstNode);
837           // } else {
838           // Descriptor srcDesc = srcNode.getDescTuple().get(0);
839           // Descriptor dstDesc = dstNode.getDescTuple().get(0);
840           // recursivelyAddCompositeRelation(md, fg, methodInfo, srcNode,
841           // dstNode, srcDesc,
842           // dstDesc);
843           // // recursiveAddRelationToLattice(1, md, srcNode, dstNode);
844           // }
845           // }
846
847         }
848       }
849     }
850
851     for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
852       FlowNode flowNode = (FlowNode) iterator.next();
853       if (flowNode.isDeclaratonNode()) {
854         CompositeLocation inferLoc = methodInfo.getInferLocation(flowNode.getDescTuple().get(0));
855         String locIdentifier = inferLoc.get(0).getLocIdentifier();
856         if (!methodLattice.containsKey(locIdentifier)) {
857           methodLattice.put(locIdentifier);
858         }
859
860       }
861     }
862
863     // create mapping from param idx to inferred composite location
864
865     int offset;
866     if (!md.isStatic()) {
867       // add 'this' reference location
868       offset = 1;
869       methodInfo.addMapParamIdxToInferLoc(0, methodInfo.getInferLocation(md.getThis()));
870     } else {
871       offset = 0;
872     }
873
874     for (int idx = 0; idx < md.numParameters(); idx++) {
875       Descriptor paramDesc = md.getParameter(idx);
876       CompositeLocation inferParamLoc = methodInfo.getInferLocation(paramDesc);
877       methodInfo.addMapParamIdxToInferLoc(idx + offset, inferParamLoc);
878     }
879
880     // calculate the initial program counter location
881     // PC location is higher than location types of all parameters
882     String pcLocSymbol = "PCLOC";
883     Map<Integer, CompositeLocation> mapParamToLoc = methodInfo.getMapParamIdxToInferLoc();
884     Set<Integer> keySet = mapParamToLoc.keySet();
885     for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
886       Integer paramIdx = (Integer) iterator.next();
887       CompositeLocation inferLoc = mapParamToLoc.get(paramIdx);
888       String paramLocLocalSymbol = inferLoc.get(0).getLocIdentifier();
889       if (!methodLattice.isGreaterThan(pcLocSymbol, paramLocLocalSymbol)) {
890         addRelationHigherToLower(methodLattice, methodInfo, pcLocSymbol, paramLocLocalSymbol);
891       }
892     }
893
894     // calculate a return location
895     // the return location type is lower than all parameters
896     if (!md.getReturnType().isVoid()) {
897
898       String returnLocSymbol = "RETURNLOC";
899
900       for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
901         Integer paramIdx = (Integer) iterator.next();
902         CompositeLocation inferLoc = mapParamToLoc.get(paramIdx);
903         String paramLocLocalSymbol = inferLoc.get(0).getLocIdentifier();
904         if (!methodLattice.isGreaterThan(paramLocLocalSymbol, returnLocSymbol)) {
905           addRelationHigherToLower(methodLattice, methodInfo, paramLocLocalSymbol, returnLocSymbol);
906         }
907       }
908     }
909
910   }
911
912   private boolean isGreaterThan(SSJavaLattice<String> methodLattice, CompositeLocation comp1,
913       CompositeLocation comp2) {
914
915     int size = comp1.getSize() >= comp2.getSize() ? comp2.getSize() : comp1.getSize();
916
917     for (int idx = 0; idx < size; idx++) {
918       Location loc1 = comp1.get(idx);
919       Location loc2 = comp2.get(idx);
920
921       Descriptor desc1 = loc1.getDescriptor();
922       Descriptor desc2 = loc2.getDescriptor();
923
924       if (!desc1.equals(desc2)) {
925         throw new Error("Fail to compare " + comp1 + " and " + comp2);
926       }
927
928       String symbol1 = loc1.getLocIdentifier();
929       String symbol2 = loc2.getLocIdentifier();
930
931       SSJavaLattice<String> lattice;
932       if (idx == 0) {
933         lattice = methodLattice;
934       } else {
935         lattice = getLattice(desc1);
936       }
937       if (symbol1.equals(symbol2)) {
938         continue;
939       } else if (lattice.isGreaterThan(symbol1, symbol2)) {
940         return true;
941       } else {
942         return false;
943       }
944
945     }
946
947     return false;
948   }
949
950   private void recursiveAddRelationToLattice(int idx, MethodDescriptor md,
951       CompositeLocation srcInferLoc, CompositeLocation dstInferLoc) throws CyclicFlowException {
952
953     String srcLocSymbol = srcInferLoc.get(idx).getLocIdentifier();
954     String dstLocSymbol = dstInferLoc.get(idx).getLocIdentifier();
955
956     if (srcLocSymbol.equals(dstLocSymbol)) {
957       recursiveAddRelationToLattice(idx + 1, md, srcInferLoc, dstInferLoc);
958     } else {
959
960       Descriptor parentDesc = srcInferLoc.get(idx).getDescriptor();
961       LocationInfo locInfo = getLocationInfo(parentDesc);
962
963       addRelationHigherToLower(getLattice(parentDesc), getLocationInfo(parentDesc), srcLocSymbol,
964           dstLocSymbol);
965     }
966
967   }
968
969   private void analyzeLatticeMethodInvocationNode(MethodDescriptor mdCaller,
970       SSJavaLattice<String> methodLattice, MethodLocationInfo methodInfo)
971       throws CyclicFlowException {
972
973     // the transformation for a call site propagates all relations between
974     // parameters from the callee
975     // if the method is virtual, it also grab all relations from any possible
976     // callees
977
978     Set<MethodInvokeNode> setMethodInvokeNode =
979         mapMethodDescriptorToMethodInvokeNodeSet.get(mdCaller);
980
981     if (setMethodInvokeNode != null) {
982
983       for (Iterator iterator = setMethodInvokeNode.iterator(); iterator.hasNext();) {
984         MethodInvokeNode min = (MethodInvokeNode) iterator.next();
985         MethodDescriptor mdCallee = min.getMethod();
986         Set<MethodDescriptor> setPossibleCallees = new HashSet<MethodDescriptor>();
987         if (mdCallee.isStatic()) {
988           setPossibleCallees.add(mdCallee);
989         } else {
990           Set<MethodDescriptor> calleeSet = ssjava.getCallGraph().getMethods(mdCallee);
991           // removes method descriptors that are not invoked by the caller
992           calleeSet.retainAll(mapMethodToCalleeSet.get(mdCaller));
993           setPossibleCallees.addAll(calleeSet);
994         }
995
996         for (Iterator iterator2 = setPossibleCallees.iterator(); iterator2.hasNext();) {
997           MethodDescriptor possibleMdCallee = (MethodDescriptor) iterator2.next();
998           propagateRelationToCaller(min, mdCaller, possibleMdCallee, methodLattice, methodInfo);
999         }
1000
1001       }
1002     }
1003
1004   }
1005
1006   private void propagateRelationToCaller(MethodInvokeNode min, MethodDescriptor mdCaller,
1007       MethodDescriptor possibleMdCallee, SSJavaLattice<String> methodLattice,
1008       MethodLocationInfo methodInfo) throws CyclicFlowException {
1009
1010     SSJavaLattice<String> calleeLattice = getMethodLattice(possibleMdCallee);
1011     MethodLocationInfo calleeLocInfo = getMethodLocationInfo(possibleMdCallee);
1012     FlowGraph calleeFlowGraph = getFlowGraph(possibleMdCallee);
1013
1014     int numParam = calleeLocInfo.getNumParam();
1015     for (int i = 0; i < numParam; i++) {
1016       CompositeLocation param1 = calleeLocInfo.getParamCompositeLocation(i);
1017       for (int k = 0; k < numParam; k++) {
1018         if (i != k) {
1019           CompositeLocation param2 = calleeLocInfo.getParamCompositeLocation(k);
1020           if (isGreaterThan(getLattice(possibleMdCallee), param1, param2)) {
1021             NodeTupleSet argDescTupleSet1 = getNodeTupleSetByArgIdx(min, i);
1022             NodeTupleSet argDescTupleSet2 = getNodeTupleSetByArgIdx(min, k);
1023
1024             // the callee has the relation in which param1 is higher than param2
1025             // therefore, the caller has to have the relation in which arg1 is
1026             // higher than arg2
1027
1028             for (Iterator<NTuple<Descriptor>> iterator = argDescTupleSet1.iterator(); iterator
1029                 .hasNext();) {
1030               NTuple<Descriptor> argDescTuple1 = iterator.next();
1031
1032               for (Iterator<NTuple<Descriptor>> iterator2 = argDescTupleSet2.iterator(); iterator2
1033                   .hasNext();) {
1034                 NTuple<Descriptor> argDescTuple2 = iterator2.next();
1035
1036                 // retreive inferred location by the local var descriptor
1037
1038                 NTuple<Location> tuple1 = getFlowGraph(mdCaller).getLocationTuple(argDescTuple1);
1039                 NTuple<Location> tuple2 = getFlowGraph(mdCaller).getLocationTuple(argDescTuple2);
1040
1041                 // CompositeLocation higherInferLoc =
1042                 // methodInfo.getInferLocation(argTuple1.get(0));
1043                 // CompositeLocation lowerInferLoc =
1044                 // methodInfo.getInferLocation(argTuple2.get(0));
1045
1046                 CompositeLocation inferLoc1 = generateInferredCompositeLocation(methodInfo, tuple1);
1047                 CompositeLocation inferLoc2 = generateInferredCompositeLocation(methodInfo, tuple2);
1048
1049                 // addRelation(methodLattice, methodInfo, inferLoc1, inferLoc2);
1050
1051                 addFlowGraphEdge(mdCaller, argDescTuple1, argDescTuple2);
1052
1053               }
1054
1055             }
1056
1057           }
1058         }
1059       }
1060     }
1061
1062   }
1063
1064   private CompositeLocation generateInferredCompositeLocation(MethodLocationInfo methodInfo,
1065       NTuple<Location> tuple) {
1066
1067     // first, retrieve inferred location by the local var descriptor
1068     CompositeLocation inferLoc = new CompositeLocation();
1069
1070     CompositeLocation localVarInferLoc =
1071         methodInfo.getInferLocation(tuple.get(0).getLocDescriptor());
1072
1073     localVarInferLoc.get(0).setLocDescriptor(tuple.get(0).getLocDescriptor());
1074
1075     for (int i = 0; i < localVarInferLoc.getSize(); i++) {
1076       inferLoc.addLocation(localVarInferLoc.get(i));
1077     }
1078     // System.out.println("@@@@@localVarInferLoc=" + localVarInferLoc);
1079
1080     for (int i = 1; i < tuple.size(); i++) {
1081       Location cur = tuple.get(i);
1082       Descriptor enclosingDesc = cur.getDescriptor();
1083       Descriptor curDesc = cur.getLocDescriptor();
1084
1085       Location inferLocElement;
1086       if (curDesc == null) {
1087         // in this case, we have a newly generated location.
1088         // System.out.println("!!! generated location=" +
1089         // cur.getLocIdentifier());
1090         inferLocElement = new Location(enclosingDesc, cur.getLocIdentifier());
1091       } else {
1092         String fieldLocSymbol =
1093             getLocationInfo(enclosingDesc).getInferLocation(curDesc).get(0).getLocIdentifier();
1094         inferLocElement = new Location(enclosingDesc, fieldLocSymbol);
1095         inferLocElement.setLocDescriptor(curDesc);
1096       }
1097
1098       inferLoc.addLocation(inferLocElement);
1099
1100     }
1101
1102     assert (inferLoc.get(0).getLocDescriptor().getSymbol() == inferLoc.get(0).getLocIdentifier());
1103     return inferLoc;
1104   }
1105
1106   private void addRelation(SSJavaLattice<String> methodLattice, MethodLocationInfo methodInfo,
1107       CompositeLocation srcInferLoc, CompositeLocation dstInferLoc) throws CyclicFlowException {
1108
1109     System.out.println("addRelation --- srcInferLoc=" + srcInferLoc + "  dstInferLoc="
1110         + dstInferLoc);
1111     String srcLocalLocSymbol = srcInferLoc.get(0).getLocIdentifier();
1112     String dstLocalLocSymbol = dstInferLoc.get(0).getLocIdentifier();
1113
1114     if (srcInferLoc.getSize() == 1 && dstInferLoc.getSize() == 1) {
1115       // add a new relation to the local lattice
1116       addRelationHigherToLower(methodLattice, methodInfo, srcLocalLocSymbol, dstLocalLocSymbol);
1117     } else if (srcInferLoc.getSize() > 1 && dstInferLoc.getSize() > 1) {
1118       // both src and dst have assigned to a composite location
1119
1120       if (!srcLocalLocSymbol.equals(dstLocalLocSymbol)) {
1121         addRelationHigherToLower(methodLattice, methodInfo, srcLocalLocSymbol, dstLocalLocSymbol);
1122       } else {
1123         recursivelyAddRelation(1, srcInferLoc, dstInferLoc);
1124       }
1125     } else {
1126       // either src or dst has assigned to a composite location
1127       if (!srcLocalLocSymbol.equals(dstLocalLocSymbol)) {
1128         addRelationHigherToLower(methodLattice, methodInfo, srcLocalLocSymbol, dstLocalLocSymbol);
1129       }
1130     }
1131
1132     System.out.println();
1133
1134   }
1135
1136   public LocationInfo getLocationInfo(Descriptor d) {
1137     if (d instanceof MethodDescriptor) {
1138       return getMethodLocationInfo((MethodDescriptor) d);
1139     } else {
1140       return getFieldLocationInfo((ClassDescriptor) d);
1141     }
1142   }
1143
1144   private MethodLocationInfo getMethodLocationInfo(MethodDescriptor md) {
1145
1146     if (!mapMethodDescToMethodLocationInfo.containsKey(md)) {
1147       mapMethodDescToMethodLocationInfo.put(md, new MethodLocationInfo(md));
1148     }
1149
1150     return mapMethodDescToMethodLocationInfo.get(md);
1151
1152   }
1153
1154   private LocationInfo getFieldLocationInfo(ClassDescriptor cd) {
1155
1156     if (!mapClassToLocationInfo.containsKey(cd)) {
1157       mapClassToLocationInfo.put(cd, new LocationInfo(cd));
1158     }
1159
1160     return mapClassToLocationInfo.get(cd);
1161
1162   }
1163
1164   private void addRelationToLattice(MethodDescriptor md, SSJavaLattice<String> methodLattice,
1165       MethodLocationInfo methodInfo, FlowNode srcNode, FlowNode dstNode) throws CyclicFlowException {
1166
1167     System.out.println();
1168     System.out.println("### addRelationToLattice src=" + srcNode + " dst=" + dstNode);
1169
1170     // add a new binary relation of dstNode < srcNode
1171     FlowGraph flowGraph = getFlowGraph(md);
1172     try {
1173       System.out.println("***** src composite case::");
1174       calculateCompositeLocation(flowGraph, methodLattice, methodInfo, srcNode);
1175
1176       CompositeLocation srcInferLoc =
1177           generateInferredCompositeLocation(methodInfo, flowGraph.getLocationTuple(srcNode));
1178       CompositeLocation dstInferLoc =
1179           generateInferredCompositeLocation(methodInfo, flowGraph.getLocationTuple(dstNode));
1180       addRelation(methodLattice, methodInfo, srcInferLoc, dstInferLoc);
1181     } catch (CyclicFlowException e) {
1182       // there is a cyclic value flow... try to calculate a composite location
1183       // for the destination node
1184       System.out.println("***** dst composite case::");
1185       calculateCompositeLocation(flowGraph, methodLattice, methodInfo, dstNode);
1186       CompositeLocation srcInferLoc =
1187           generateInferredCompositeLocation(methodInfo, flowGraph.getLocationTuple(srcNode));
1188       CompositeLocation dstInferLoc =
1189           generateInferredCompositeLocation(methodInfo, flowGraph.getLocationTuple(dstNode));
1190       try {
1191         addRelation(methodLattice, methodInfo, srcInferLoc, dstInferLoc);
1192       } catch (CyclicFlowException e1) {
1193         throw new Error("Failed to merge cyclic value flows into a shared location.");
1194       }
1195     }
1196
1197   }
1198
1199   private void recursivelyAddRelation(int idx, CompositeLocation srcInferLoc,
1200       CompositeLocation dstInferLoc) throws CyclicFlowException {
1201
1202     String srcLocSymbol = srcInferLoc.get(idx).getLocIdentifier();
1203     String dstLocSymbol = dstInferLoc.get(idx).getLocIdentifier();
1204
1205     Descriptor parentDesc = srcInferLoc.get(idx).getDescriptor();
1206
1207     if (srcLocSymbol.equals(dstLocSymbol)) {
1208       // check if it is the case of shared location
1209       if (srcInferLoc.getSize() == (idx + 1) && dstInferLoc.getSize() == (idx + 1)) {
1210         Location inferLocElement = srcInferLoc.get(idx);
1211         System.out.println("SET SHARED LOCATION=" + inferLocElement);
1212         getLattice(inferLocElement.getDescriptor())
1213             .addSharedLoc(inferLocElement.getLocIdentifier());
1214       } else if (srcInferLoc.getSize() > (idx + 1) && dstInferLoc.getSize() > (idx + 1)) {
1215         recursivelyAddRelation(idx + 1, srcInferLoc, dstInferLoc);
1216       }
1217     } else {
1218       addRelationHigherToLower(getLattice(parentDesc), getLocationInfo(parentDesc), srcLocSymbol,
1219           dstLocSymbol);
1220     }
1221   }
1222
1223   private void recursivelyAddCompositeRelation(MethodDescriptor md, FlowGraph flowGraph,
1224       MethodLocationInfo methodInfo, FlowNode srcNode, FlowNode dstNode, Descriptor srcDesc,
1225       Descriptor dstDesc) throws CyclicFlowException {
1226
1227     CompositeLocation inferSrcLoc;
1228     CompositeLocation inferDstLoc = methodInfo.getInferLocation(dstDesc);
1229
1230     if (srcNode.getDescTuple().size() > 1) {
1231       // field access
1232       inferSrcLoc = new CompositeLocation();
1233
1234       NTuple<Location> locTuple = flowGraph.getLocationTuple(srcNode);
1235       for (int i = 0; i < locTuple.size(); i++) {
1236         inferSrcLoc.addLocation(locTuple.get(i));
1237       }
1238
1239     } else {
1240       inferSrcLoc = methodInfo.getInferLocation(srcDesc);
1241     }
1242
1243     if (dstNode.getDescTuple().size() > 1) {
1244       // field access
1245       inferDstLoc = new CompositeLocation();
1246
1247       NTuple<Location> locTuple = flowGraph.getLocationTuple(dstNode);
1248       for (int i = 0; i < locTuple.size(); i++) {
1249         inferDstLoc.addLocation(locTuple.get(i));
1250       }
1251
1252     } else {
1253       inferDstLoc = methodInfo.getInferLocation(dstDesc);
1254     }
1255
1256     recursiveAddRelationToLattice(1, md, inferSrcLoc, inferDstLoc);
1257   }
1258
1259   private void addPrefixMapping(Map<NTuple<Location>, Set<NTuple<Location>>> map,
1260       NTuple<Location> prefix, NTuple<Location> element) {
1261
1262     if (!map.containsKey(prefix)) {
1263       map.put(prefix, new HashSet<NTuple<Location>>());
1264     }
1265     map.get(prefix).add(element);
1266   }
1267
1268   private boolean calculateCompositeLocation(FlowGraph flowGraph,
1269       SSJavaLattice<String> methodLattice, MethodLocationInfo methodInfo, FlowNode flowNode)
1270       throws CyclicFlowException {
1271
1272     Descriptor localVarDesc = flowNode.getDescTuple().get(0);
1273     NTuple<Location> flowNodelocTuple = flowGraph.getLocationTuple(flowNode);
1274
1275     if (localVarDesc.equals(methodInfo.getMethodDesc())) {
1276       return false;
1277     }
1278
1279     Set<FlowNode> inNodeSet = flowGraph.getIncomingFlowNodeSet(flowNode);
1280     Set<FlowNode> reachableNodeSet = flowGraph.getReachableFlowNodeSet(flowNode);
1281
1282     Map<NTuple<Location>, Set<NTuple<Location>>> mapPrefixToIncomingLocTupleSet =
1283         new HashMap<NTuple<Location>, Set<NTuple<Location>>>();
1284
1285     List<NTuple<Location>> prefixList = new ArrayList<NTuple<Location>>();
1286
1287     for (Iterator iterator = inNodeSet.iterator(); iterator.hasNext();) {
1288       FlowNode inNode = (FlowNode) iterator.next();
1289       NTuple<Location> inNodeTuple = flowGraph.getLocationTuple(inNode);
1290
1291       CompositeLocation inNodeInferredLoc =
1292           generateInferredCompositeLocation(methodInfo, inNodeTuple);
1293
1294       NTuple<Location> inNodeInferredLocTuple = inNodeInferredLoc.getTuple();
1295
1296       for (int i = 1; i < inNodeInferredLocTuple.size(); i++) {
1297         NTuple<Location> prefix = inNodeInferredLocTuple.subList(0, i);
1298         if (!prefixList.contains(prefix)) {
1299           prefixList.add(prefix);
1300         }
1301         addPrefixMapping(mapPrefixToIncomingLocTupleSet, prefix, inNodeInferredLocTuple);
1302       }
1303     }
1304
1305     Collections.sort(prefixList, new Comparator<NTuple<Location>>() {
1306       public int compare(NTuple<Location> arg0, NTuple<Location> arg1) {
1307         int s0 = arg0.size();
1308         int s1 = arg1.size();
1309         if (s0 > s1) {
1310           return -1;
1311         } else if (s0 == s1) {
1312           return 0;
1313         } else {
1314           return 1;
1315         }
1316       }
1317     });
1318
1319     // find out reachable nodes that have the longest common prefix
1320     for (int i = 0; i < prefixList.size(); i++) {
1321       NTuple<Location> curPrefix = prefixList.get(i);
1322       Set<NTuple<Location>> reachableCommonPrefixSet = new HashSet<NTuple<Location>>();
1323
1324       for (Iterator iterator2 = reachableNodeSet.iterator(); iterator2.hasNext();) {
1325         FlowNode reachableNode = (FlowNode) iterator2.next();
1326         NTuple<Location> reachLocTuple = flowGraph.getLocationTuple(reachableNode);
1327         CompositeLocation reachLocInferLoc =
1328             generateInferredCompositeLocation(methodInfo, reachLocTuple);
1329         if (reachLocInferLoc.getTuple().startsWith(curPrefix)) {
1330           reachableCommonPrefixSet.add(reachLocTuple);
1331         }
1332       }
1333
1334       if (!reachableCommonPrefixSet.isEmpty()) {
1335         // found reachable nodes that start with the prefix curPrefix
1336         // need to assign a composite location
1337
1338         // first, check if there are more than one the set of locations that has
1339         // the same length of the longest reachable prefix, no way to assign
1340         // a composite location to the input local var
1341         prefixSanityCheck(prefixList, i, flowGraph, reachableNodeSet);
1342
1343         Set<NTuple<Location>> incomingCommonPrefixSet =
1344             mapPrefixToIncomingLocTupleSet.get(curPrefix);
1345
1346         int idx = curPrefix.size();
1347         NTuple<Location> element = incomingCommonPrefixSet.iterator().next();
1348         Descriptor desc = element.get(idx).getDescriptor();
1349
1350         SSJavaLattice<String> lattice = getLattice(desc);
1351         LocationInfo locInfo = getLocationInfo(desc);
1352
1353         CompositeLocation inferLocation =
1354             generateInferredCompositeLocation(methodInfo, flowNodelocTuple);
1355
1356         // methodInfo.getInferLocation(localVarDesc);
1357         CompositeLocation newInferLocation = new CompositeLocation();
1358
1359         if (inferLocation.getTuple().startsWith(curPrefix)) {
1360           // the same infer location is already existed. no need to do
1361           // anything
1362           return true;
1363         } else {
1364           // assign a new composite location
1365
1366           // String oldMethodLocationSymbol =
1367           // inferLocation.get(0).getLocIdentifier();
1368           String newLocSymbol = "Loc" + (SSJavaLattice.seed++);
1369           for (int locIdx = 0; locIdx < curPrefix.size(); locIdx++) {
1370             newInferLocation.addLocation(curPrefix.get(locIdx));
1371           }
1372           Location newLocationElement = new Location(desc, newLocSymbol);
1373           newInferLocation.addLocation(newLocationElement);
1374
1375           // maps local variable to location types of the common prefix
1376           methodInfo.mapDescriptorToLocation(localVarDesc, newInferLocation.clone());
1377
1378           // methodInfo.mapDescriptorToLocation(localVarDesc, newInferLocation);
1379           addMapLocSymbolToInferredLocation(methodInfo.getMethodDesc(), localVarDesc,
1380               newInferLocation);
1381           methodInfo.removeMaplocalVarToLocSet(localVarDesc);
1382
1383           // add the field/var descriptor to the set of the location symbol
1384           int lastIdx = flowNode.getDescTuple().size() - 1;
1385           Descriptor lastFlowNodeDesc = flowNode.getDescTuple().get(lastIdx);
1386           Descriptor enclosinglastLastFlowNodeDesc = flowNodelocTuple.get(lastIdx).getDescriptor();
1387
1388           CompositeLocation newlyInferredLocForFlowNode =
1389               generateInferredCompositeLocation(methodInfo, flowNodelocTuple);
1390           Location lastInferLocElement =
1391               newlyInferredLocForFlowNode.get(newlyInferredLocForFlowNode.getSize() - 1);
1392           Descriptor enclosingLastInferLocElement = lastInferLocElement.getDescriptor();
1393
1394           // getLocationInfo(enclosingLastInferLocElement).addMapLocSymbolToDescSet(
1395           // lastInferLocElement.getLocIdentifier(), lastFlowNodeDesc);
1396           getLocationInfo(enclosingLastInferLocElement).addMapLocSymbolToRelatedInferLoc(
1397               lastInferLocElement.getLocIdentifier(), enclosinglastLastFlowNodeDesc,
1398               lastFlowNodeDesc);
1399
1400           // clean up the previous location
1401           // Location prevInferLocElement =
1402           // inferLocation.get(inferLocation.getSize() - 1);
1403           // Descriptor prevEnclosingDesc = prevInferLocElement.getDescriptor();
1404           //
1405           // SSJavaLattice<String> targetLattice;
1406           // LocationInfo targetInfo;
1407           // if (prevEnclosingDesc.equals(methodInfo.getMethodDesc())) {
1408           // targetLattice = methodLattice;
1409           // targetInfo = methodInfo;
1410           // } else {
1411           // targetLattice = getLattice(prevInferLocElement.getDescriptor());
1412           // targetInfo = getLocationInfo(prevInferLocElement.getDescriptor());
1413           // }
1414           //
1415           // Set<Pair<Descriptor, Descriptor>> associstedDescSet =
1416           // targetInfo.getRelatedInferLocSet(prevInferLocElement.getLocIdentifier());
1417           //
1418           // if (associstedDescSet.size() == 1) {
1419           // targetLattice.remove(prevInferLocElement.getLocIdentifier());
1420           // } else {
1421           // associstedDescSet.remove(lastFlowNodeDesc);
1422           // }
1423
1424         }
1425
1426         System.out.println("ASSIGN NEW COMPOSITE LOCATION =" + newInferLocation + "    to "
1427             + flowNode);
1428
1429         String newlyInsertedLocName =
1430             newInferLocation.get(newInferLocation.getSize() - 1).getLocIdentifier();
1431
1432         System.out.println("-- add in-flow");
1433         for (Iterator iterator = incomingCommonPrefixSet.iterator(); iterator.hasNext();) {
1434           NTuple<Location> tuple = (NTuple<Location>) iterator.next();
1435           Location loc = tuple.get(idx);
1436           String higher = loc.getLocIdentifier();
1437           addRelationHigherToLower(lattice, locInfo, higher, newlyInsertedLocName);
1438         }
1439
1440         System.out.println("-- add out flow");
1441         for (Iterator iterator = reachableCommonPrefixSet.iterator(); iterator.hasNext();) {
1442           NTuple<Location> tuple = (NTuple<Location>) iterator.next();
1443           if (tuple.size() > idx) {
1444             Location loc = tuple.get(idx);
1445             String lower = loc.getLocIdentifier();
1446             // String lower =
1447             // locInfo.getFieldInferLocation(loc.getLocDescriptor()).getLocIdentifier();
1448             addRelationHigherToLower(lattice, locInfo, newlyInsertedLocName, lower);
1449           }
1450         }
1451
1452         return true;
1453       }
1454
1455     }
1456
1457     return false;
1458
1459   }
1460
1461   private void addMapLocSymbolToInferredLocation(MethodDescriptor md, Descriptor localVar,
1462       CompositeLocation inferLoc) {
1463
1464     Location locElement = inferLoc.get((inferLoc.getSize() - 1));
1465     Descriptor enclosingDesc = locElement.getDescriptor();
1466     LocationInfo locInfo = getLocationInfo(enclosingDesc);
1467     locInfo.addMapLocSymbolToRelatedInferLoc(locElement.getLocIdentifier(), md, localVar);
1468   }
1469
1470   private boolean isCompositeLocation(CompositeLocation cl) {
1471     return cl.getSize() > 1;
1472   }
1473
1474   private boolean containsNonPrimitiveElement(Set<Descriptor> descSet) {
1475     for (Iterator iterator = descSet.iterator(); iterator.hasNext();) {
1476       Descriptor desc = (Descriptor) iterator.next();
1477
1478       if (desc.equals(LocationInference.GLOBALDESC)) {
1479         return true;
1480       } else if (desc instanceof VarDescriptor) {
1481         if (!((VarDescriptor) desc).getType().isPrimitive()) {
1482           return true;
1483         }
1484       } else if (desc instanceof FieldDescriptor) {
1485         if (!((FieldDescriptor) desc).getType().isPrimitive()) {
1486           return true;
1487         }
1488       }
1489
1490     }
1491     return false;
1492   }
1493
1494   private void addRelationHigherToLower(SSJavaLattice<String> lattice, LocationInfo locInfo,
1495       String higher, String lower) throws CyclicFlowException {
1496
1497     System.out.println("---addRelationHigherToLower " + higher + " -> " + lower
1498         + " to the lattice of " + locInfo.getDescIdentifier());
1499     // if (higher.equals(lower) && lattice.isSharedLoc(higher)) {
1500     // return;
1501     // }
1502     Set<String> cycleElementSet = lattice.getPossibleCycleElements(higher, lower);
1503
1504     boolean hasNonPrimitiveElement = false;
1505     for (Iterator iterator = cycleElementSet.iterator(); iterator.hasNext();) {
1506       String cycleElementLocSymbol = (String) iterator.next();
1507
1508       Set<Descriptor> descSet = locInfo.getDescSet(cycleElementLocSymbol);
1509       if (containsNonPrimitiveElement(descSet)) {
1510         hasNonPrimitiveElement = true;
1511         break;
1512       }
1513     }
1514
1515     if (hasNonPrimitiveElement) {
1516       System.out.println("#Check cycle= " + lower + " < " + higher + "     cycleElementSet="
1517           + cycleElementSet);
1518       // if there is non-primitive element in the cycle, no way to merge cyclic
1519       // elements into the shared location
1520       throw new CyclicFlowException();
1521     }
1522
1523     if (cycleElementSet.size() > 0) {
1524
1525       String newSharedLoc = "SharedLoc" + (SSJavaLattice.seed++);
1526
1527       System.out.println("---ASSIGN NEW SHARED LOC=" + newSharedLoc + "   to  " + cycleElementSet);
1528       lattice.mergeIntoSharedLocation(cycleElementSet, newSharedLoc);
1529
1530       for (Iterator iterator = cycleElementSet.iterator(); iterator.hasNext();) {
1531         String oldLocSymbol = (String) iterator.next();
1532
1533         Set<Pair<Descriptor, Descriptor>> inferLocSet = locInfo.getRelatedInferLocSet(oldLocSymbol);
1534         System.out.println("---update related locations=" + inferLocSet);
1535         for (Iterator iterator2 = inferLocSet.iterator(); iterator2.hasNext();) {
1536           Pair<Descriptor, Descriptor> pair = (Pair<Descriptor, Descriptor>) iterator2.next();
1537           Descriptor enclosingDesc = pair.getFirst();
1538           Descriptor desc = pair.getSecond();
1539
1540           CompositeLocation inferLoc;
1541           if (curMethodInfo.md.equals(enclosingDesc)) {
1542             inferLoc = curMethodInfo.getInferLocation(desc);
1543           } else {
1544             inferLoc = getLocationInfo(enclosingDesc).getInferLocation(desc);
1545           }
1546
1547           Location locElement = inferLoc.get(inferLoc.getSize() - 1);
1548
1549           locElement.setLocIdentifier(newSharedLoc);
1550           locInfo.addMapLocSymbolToRelatedInferLoc(newSharedLoc, enclosingDesc, desc);
1551
1552           if (curMethodInfo.md.equals(enclosingDesc)) {
1553             inferLoc = curMethodInfo.getInferLocation(desc);
1554           } else {
1555             inferLoc = getLocationInfo(enclosingDesc).getInferLocation(desc);
1556           }
1557           System.out.println("---New Infer Loc=" + inferLoc);
1558
1559         }
1560         locInfo.removeRelatedInferLocSet(oldLocSymbol, newSharedLoc);
1561
1562       }
1563
1564       lattice.addSharedLoc(newSharedLoc);
1565
1566     } else if (!lattice.isGreaterThan(higher, lower)) {
1567       lattice.addRelationHigherToLower(higher, lower);
1568     }
1569   }
1570
1571   private void replaceOldLocWithNewLoc(SSJavaLattice<String> methodLattice, String oldLocSymbol,
1572       String newLocSymbol) {
1573
1574     if (methodLattice.containsKey(oldLocSymbol)) {
1575       methodLattice.substituteLocation(oldLocSymbol, newLocSymbol);
1576     }
1577
1578   }
1579
1580   private void prefixSanityCheck(List<NTuple<Location>> prefixList, int curIdx,
1581       FlowGraph flowGraph, Set<FlowNode> reachableNodeSet) {
1582
1583     NTuple<Location> curPrefix = prefixList.get(curIdx);
1584
1585     for (int i = curIdx + 1; i < prefixList.size(); i++) {
1586       NTuple<Location> prefixTuple = prefixList.get(i);
1587
1588       if (curPrefix.startsWith(prefixTuple)) {
1589         continue;
1590       }
1591
1592       for (Iterator iterator2 = reachableNodeSet.iterator(); iterator2.hasNext();) {
1593         FlowNode reachableNode = (FlowNode) iterator2.next();
1594         NTuple<Location> reachLocTuple = flowGraph.getLocationTuple(reachableNode);
1595         if (reachLocTuple.startsWith(prefixTuple)) {
1596           // TODO
1597           throw new Error("Failed to generate a composite location");
1598         }
1599       }
1600     }
1601   }
1602
1603   public boolean isPrimitiveLocalVariable(FlowNode node) {
1604     VarDescriptor varDesc = (VarDescriptor) node.getDescTuple().get(0);
1605     return varDesc.getType().isPrimitive();
1606   }
1607
1608   private SSJavaLattice<String> getLattice(Descriptor d) {
1609     if (d instanceof MethodDescriptor) {
1610       return getMethodLattice((MethodDescriptor) d);
1611     } else {
1612       return getFieldLattice((ClassDescriptor) d);
1613     }
1614   }
1615
1616   private SSJavaLattice<String> getMethodLattice(MethodDescriptor md) {
1617     if (!md2lattice.containsKey(md)) {
1618       md2lattice.put(md, new SSJavaLattice<String>(SSJavaAnalysis.TOP, SSJavaAnalysis.BOTTOM));
1619     }
1620     return md2lattice.get(md);
1621   }
1622
1623   private void setMethodLattice(MethodDescriptor md, SSJavaLattice<String> lattice) {
1624     md2lattice.put(md, lattice);
1625   }
1626
1627   private void extractRelationFromFieldFlows(ClassDescriptor cd, FlowNode srcNode,
1628       FlowNode dstNode, int idx) throws CyclicFlowException {
1629
1630     if (srcNode.getDescTuple().get(idx).equals(dstNode.getDescTuple().get(idx))
1631         && srcNode.getDescTuple().size() > (idx + 1) && dstNode.getDescTuple().size() > (idx + 1)) {
1632       // value flow between fields: we don't need to add a binary relation
1633       // for this case
1634
1635       Descriptor desc = srcNode.getDescTuple().get(idx);
1636       ClassDescriptor classDesc;
1637
1638       if (idx == 0) {
1639         classDesc = ((VarDescriptor) desc).getType().getClassDesc();
1640       } else {
1641         classDesc = ((FieldDescriptor) desc).getType().getClassDesc();
1642       }
1643
1644       extractRelationFromFieldFlows(classDesc, srcNode, dstNode, idx + 1);
1645
1646     } else {
1647
1648       Descriptor srcFieldDesc = srcNode.getDescTuple().get(idx);
1649       Descriptor dstFieldDesc = dstNode.getDescTuple().get(idx);
1650
1651       // add a new binary relation of dstNode < srcNode
1652       SSJavaLattice<String> fieldLattice = getFieldLattice(cd);
1653       LocationInfo fieldInfo = getFieldLocationInfo(cd);
1654
1655       String srcSymbol = fieldInfo.getFieldInferLocation(srcFieldDesc).getLocIdentifier();
1656       String dstSymbol = fieldInfo.getFieldInferLocation(dstFieldDesc).getLocIdentifier();
1657
1658       addRelationHigherToLower(fieldLattice, fieldInfo, srcSymbol, dstSymbol);
1659
1660     }
1661
1662   }
1663
1664   public SSJavaLattice<String> getFieldLattice(ClassDescriptor cd) {
1665     if (!cd2lattice.containsKey(cd)) {
1666       cd2lattice.put(cd, new SSJavaLattice<String>(SSJavaAnalysis.TOP, SSJavaAnalysis.BOTTOM));
1667     }
1668     return cd2lattice.get(cd);
1669   }
1670
1671   public void constructFlowGraph() {
1672
1673     setupToAnalyze();
1674
1675     Set<MethodDescriptor> visited = new HashSet<MethodDescriptor>();
1676     Set<MethodDescriptor> reachableCallee = new HashSet<MethodDescriptor>();
1677
1678     while (!toAnalyzeIsEmpty()) {
1679       ClassDescriptor cd = toAnalyzeNext();
1680
1681       setupToAnalazeMethod(cd);
1682       toanalyzeMethodList.removeAll(visited);
1683
1684       while (!toAnalyzeMethodIsEmpty()) {
1685         MethodDescriptor md = toAnalyzeMethodNext();
1686         if ((!visited.contains(md))
1687             && (ssjava.needTobeAnnotated(md) || reachableCallee.contains(md))) {
1688           if (state.SSJAVADEBUG) {
1689             System.out.println();
1690             System.out.println("SSJAVA: Constructing a flow graph: " + md);
1691           }
1692
1693           // creates a mapping from a method descriptor to virtual methods
1694           Set<MethodDescriptor> setPossibleCallees = new HashSet<MethodDescriptor>();
1695           if (md.isStatic()) {
1696             setPossibleCallees.add(md);
1697           } else {
1698             setPossibleCallees.addAll(ssjava.getCallGraph().getMethods(md));
1699           }
1700
1701           Set<MethodDescriptor> calleeSet = ssjava.getCallGraph().getCalleeSet(md);
1702           Set<MethodDescriptor> needToAnalyzeCalleeSet = new HashSet<MethodDescriptor>();
1703
1704           for (Iterator iterator = calleeSet.iterator(); iterator.hasNext();) {
1705             MethodDescriptor calleemd = (MethodDescriptor) iterator.next();
1706             if ((!ssjava.isTrustMethod(calleemd))
1707                 && (!ssjava.isSSJavaUtil(calleemd.getClassDesc()))) {
1708               if (!visited.contains(calleemd)) {
1709                 toanalyzeMethodList.add(calleemd);
1710               }
1711               reachableCallee.add(calleemd);
1712               needToAnalyzeCalleeSet.add(calleemd);
1713             }
1714           }
1715
1716           mapMethodToCalleeSet.put(md, needToAnalyzeCalleeSet);
1717
1718           // creates a mapping from a parameter descriptor to its index
1719           Map<Descriptor, Integer> mapParamDescToIdx = new HashMap<Descriptor, Integer>();
1720           int offset = md.isStatic() ? 0 : 1;
1721           for (int i = 0; i < md.numParameters(); i++) {
1722             Descriptor paramDesc = (Descriptor) md.getParameter(i);
1723             mapParamDescToIdx.put(paramDesc, new Integer(i + offset));
1724           }
1725
1726           FlowGraph fg = new FlowGraph(md, mapParamDescToIdx);
1727           mapMethodDescriptorToFlowGraph.put(md, fg);
1728
1729           visited.add(md);
1730           analyzeMethodBody(cd, md);
1731
1732         }
1733       }
1734     }
1735
1736     _debug_printGraph();
1737   }
1738
1739   private void analyzeMethodBody(ClassDescriptor cd, MethodDescriptor md) {
1740     BlockNode bn = state.getMethodBody(md);
1741     NodeTupleSet implicitFlowTupleSet = new NodeTupleSet();
1742     analyzeFlowBlockNode(md, md.getParameterTable(), bn, implicitFlowTupleSet);
1743   }
1744
1745   private void analyzeFlowBlockNode(MethodDescriptor md, SymbolTable nametable, BlockNode bn,
1746       NodeTupleSet implicitFlowTupleSet) {
1747
1748     bn.getVarTable().setParent(nametable);
1749     for (int i = 0; i < bn.size(); i++) {
1750       BlockStatementNode bsn = bn.get(i);
1751       analyzeBlockStatementNode(md, bn.getVarTable(), bsn, implicitFlowTupleSet);
1752     }
1753
1754   }
1755
1756   private void analyzeBlockStatementNode(MethodDescriptor md, SymbolTable nametable,
1757       BlockStatementNode bsn, NodeTupleSet implicitFlowTupleSet) {
1758
1759     switch (bsn.kind()) {
1760     case Kind.BlockExpressionNode:
1761       analyzeBlockExpressionNode(md, nametable, (BlockExpressionNode) bsn, implicitFlowTupleSet);
1762       break;
1763
1764     case Kind.DeclarationNode:
1765       analyzeFlowDeclarationNode(md, nametable, (DeclarationNode) bsn, implicitFlowTupleSet);
1766       break;
1767
1768     case Kind.IfStatementNode:
1769       analyzeFlowIfStatementNode(md, nametable, (IfStatementNode) bsn, implicitFlowTupleSet);
1770       break;
1771
1772     case Kind.LoopNode:
1773       analyzeFlowLoopNode(md, nametable, (LoopNode) bsn, implicitFlowTupleSet);
1774       break;
1775
1776     case Kind.ReturnNode:
1777       analyzeFlowReturnNode(md, nametable, (ReturnNode) bsn, implicitFlowTupleSet);
1778       break;
1779
1780     case Kind.SubBlockNode:
1781       analyzeFlowSubBlockNode(md, nametable, (SubBlockNode) bsn, implicitFlowTupleSet);
1782       break;
1783
1784     case Kind.ContinueBreakNode:
1785       break;
1786
1787     case Kind.SwitchStatementNode:
1788       analyzeSwitchStatementNode(md, nametable, (SwitchStatementNode) bsn);
1789       break;
1790
1791     }
1792
1793   }
1794
1795   private void analyzeSwitchStatementNode(MethodDescriptor md, SymbolTable nametable,
1796       SwitchStatementNode bsn) {
1797     // TODO Auto-generated method stub
1798   }
1799
1800   private void analyzeFlowSubBlockNode(MethodDescriptor md, SymbolTable nametable,
1801       SubBlockNode sbn, NodeTupleSet implicitFlowTupleSet) {
1802     analyzeFlowBlockNode(md, nametable, sbn.getBlockNode(), implicitFlowTupleSet);
1803   }
1804
1805   private void analyzeFlowReturnNode(MethodDescriptor md, SymbolTable nametable, ReturnNode rn,
1806       NodeTupleSet implicitFlowTupleSet) {
1807
1808     ExpressionNode returnExp = rn.getReturnExpression();
1809
1810     if (returnExp != null) {
1811       NodeTupleSet nodeSet = new NodeTupleSet();
1812       analyzeFlowExpressionNode(md, nametable, returnExp, nodeSet, false);
1813
1814       FlowGraph fg = getFlowGraph(md);
1815
1816       // annotate the elements of the node set as the return location
1817       for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
1818         NTuple<Descriptor> returnDescTuple = (NTuple<Descriptor>) iterator.next();
1819         fg.setReturnFlowNode(returnDescTuple);
1820         for (Iterator iterator2 = implicitFlowTupleSet.iterator(); iterator2.hasNext();) {
1821           NTuple<Descriptor> implicitFlowDescTuple = (NTuple<Descriptor>) iterator2.next();
1822           fg.addValueFlowEdge(implicitFlowDescTuple, returnDescTuple);
1823         }
1824       }
1825     }
1826
1827   }
1828
1829   private void analyzeFlowLoopNode(MethodDescriptor md, SymbolTable nametable, LoopNode ln,
1830       NodeTupleSet implicitFlowTupleSet) {
1831
1832     if (ln.getType() == LoopNode.WHILELOOP || ln.getType() == LoopNode.DOWHILELOOP) {
1833
1834       NodeTupleSet condTupleNode = new NodeTupleSet();
1835       analyzeFlowExpressionNode(md, nametable, ln.getCondition(), condTupleNode, null,
1836           implicitFlowTupleSet, false);
1837       condTupleNode.addTupleSet(implicitFlowTupleSet);
1838
1839       // add edges from condNodeTupleSet to all nodes of conditional nodes
1840       analyzeFlowBlockNode(md, nametable, ln.getBody(), condTupleNode);
1841
1842     } else {
1843       // check 'for loop' case
1844       BlockNode bn = ln.getInitializer();
1845       bn.getVarTable().setParent(nametable);
1846       for (int i = 0; i < bn.size(); i++) {
1847         BlockStatementNode bsn = bn.get(i);
1848         analyzeBlockStatementNode(md, bn.getVarTable(), bsn, implicitFlowTupleSet);
1849       }
1850
1851       NodeTupleSet condTupleNode = new NodeTupleSet();
1852       analyzeFlowExpressionNode(md, bn.getVarTable(), ln.getCondition(), condTupleNode, null,
1853           implicitFlowTupleSet, false);
1854       condTupleNode.addTupleSet(implicitFlowTupleSet);
1855
1856       analyzeFlowBlockNode(md, bn.getVarTable(), ln.getUpdate(), condTupleNode);
1857       analyzeFlowBlockNode(md, bn.getVarTable(), ln.getBody(), condTupleNode);
1858
1859     }
1860
1861   }
1862
1863   private void analyzeFlowIfStatementNode(MethodDescriptor md, SymbolTable nametable,
1864       IfStatementNode isn, NodeTupleSet implicitFlowTupleSet) {
1865
1866     NodeTupleSet condTupleNode = new NodeTupleSet();
1867     analyzeFlowExpressionNode(md, nametable, isn.getCondition(), condTupleNode, null,
1868         implicitFlowTupleSet, false);
1869
1870     // add edges from condNodeTupleSet to all nodes of conditional nodes
1871     condTupleNode.addTupleSet(implicitFlowTupleSet);
1872     analyzeFlowBlockNode(md, nametable, isn.getTrueBlock(), condTupleNode);
1873
1874     if (isn.getFalseBlock() != null) {
1875       analyzeFlowBlockNode(md, nametable, isn.getFalseBlock(), condTupleNode);
1876     }
1877
1878   }
1879
1880   private void analyzeFlowDeclarationNode(MethodDescriptor md, SymbolTable nametable,
1881       DeclarationNode dn, NodeTupleSet implicitFlowTupleSet) {
1882
1883     VarDescriptor vd = dn.getVarDescriptor();
1884     mapDescToDefinitionLine.put(vd, dn.getNumLine());
1885     NTuple<Descriptor> tupleLHS = new NTuple<Descriptor>();
1886     tupleLHS.add(vd);
1887     FlowNode fn = getFlowGraph(md).createNewFlowNode(tupleLHS);
1888     fn.setDeclarationNode();
1889
1890     if (dn.getExpression() != null) {
1891
1892       NodeTupleSet tupleSetRHS = new NodeTupleSet();
1893       analyzeFlowExpressionNode(md, nametable, dn.getExpression(), tupleSetRHS, null,
1894           implicitFlowTupleSet, false);
1895
1896       // add a new flow edge from rhs to lhs
1897       for (Iterator<NTuple<Descriptor>> iter = tupleSetRHS.iterator(); iter.hasNext();) {
1898         NTuple<Descriptor> from = iter.next();
1899         addFlowGraphEdge(md, from, tupleLHS);
1900       }
1901
1902     }
1903
1904   }
1905
1906   private void analyzeBlockExpressionNode(MethodDescriptor md, SymbolTable nametable,
1907       BlockExpressionNode ben, NodeTupleSet implicitFlowTupleSet) {
1908     analyzeFlowExpressionNode(md, nametable, ben.getExpression(), null, null, implicitFlowTupleSet,
1909         false);
1910   }
1911
1912   private NTuple<Descriptor> analyzeFlowExpressionNode(MethodDescriptor md, SymbolTable nametable,
1913       ExpressionNode en, NodeTupleSet nodeSet, boolean isLHS) {
1914     return analyzeFlowExpressionNode(md, nametable, en, nodeSet, null, new NodeTupleSet(), isLHS);
1915   }
1916
1917   private NTuple<Descriptor> analyzeFlowExpressionNode(MethodDescriptor md, SymbolTable nametable,
1918       ExpressionNode en, NodeTupleSet nodeSet, NTuple<Descriptor> base,
1919       NodeTupleSet implicitFlowTupleSet, boolean isLHS) {
1920
1921     // note that expression node can create more than one flow node
1922     // nodeSet contains of flow nodes
1923     // base is always assigned to null except the case of a name node!
1924
1925     NTuple<Descriptor> flowTuple;
1926
1927     switch (en.kind()) {
1928
1929     case Kind.AssignmentNode:
1930       analyzeFlowAssignmentNode(md, nametable, (AssignmentNode) en, nodeSet, base,
1931           implicitFlowTupleSet);
1932       break;
1933
1934     case Kind.FieldAccessNode:
1935       flowTuple =
1936           analyzeFlowFieldAccessNode(md, nametable, (FieldAccessNode) en, nodeSet, base,
1937               implicitFlowTupleSet, isLHS);
1938       if (flowTuple != null) {
1939         nodeSet.addTuple(flowTuple);
1940       }
1941       return flowTuple;
1942
1943     case Kind.NameNode:
1944       NodeTupleSet nameNodeSet = new NodeTupleSet();
1945       flowTuple =
1946           analyzeFlowNameNode(md, nametable, (NameNode) en, nameNodeSet, base, implicitFlowTupleSet);
1947       if (flowTuple != null) {
1948         nodeSet.addTuple(flowTuple);
1949       }
1950       return flowTuple;
1951
1952     case Kind.OpNode:
1953       analyzeFlowOpNode(md, nametable, (OpNode) en, nodeSet, implicitFlowTupleSet);
1954       break;
1955
1956     case Kind.CreateObjectNode:
1957       analyzeCreateObjectNode(md, nametable, (CreateObjectNode) en);
1958       break;
1959
1960     case Kind.ArrayAccessNode:
1961       analyzeFlowArrayAccessNode(md, nametable, (ArrayAccessNode) en, nodeSet, isLHS);
1962       break;
1963
1964     case Kind.LiteralNode:
1965       analyzeLiteralNode(md, nametable, (LiteralNode) en);
1966       break;
1967
1968     case Kind.MethodInvokeNode:
1969       analyzeFlowMethodInvokeNode(md, nametable, (MethodInvokeNode) en, implicitFlowTupleSet);
1970       break;
1971
1972     case Kind.TertiaryNode:
1973       analyzeFlowTertiaryNode(md, nametable, (TertiaryNode) en, nodeSet, implicitFlowTupleSet);
1974       break;
1975
1976     case Kind.CastNode:
1977       analyzeFlowCastNode(md, nametable, (CastNode) en, nodeSet, base, implicitFlowTupleSet);
1978       break;
1979     // case Kind.InstanceOfNode:
1980     // checkInstanceOfNode(md, nametable, (InstanceOfNode) en, td);
1981     // return null;
1982
1983     // case Kind.ArrayInitializerNode:
1984     // checkArrayInitializerNode(md, nametable, (ArrayInitializerNode) en,
1985     // td);
1986     // return null;
1987
1988     // case Kind.ClassTypeNode:
1989     // checkClassTypeNode(md, nametable, (ClassTypeNode) en, td);
1990     // return null;
1991
1992     // case Kind.OffsetNode:
1993     // checkOffsetNode(md, nametable, (OffsetNode)en, td);
1994     // return null;
1995
1996     }
1997     return null;
1998
1999   }
2000
2001   private void analyzeFlowCastNode(MethodDescriptor md, SymbolTable nametable, CastNode cn,
2002       NodeTupleSet nodeSet, NTuple<Descriptor> base, NodeTupleSet implicitFlowTupleSet) {
2003
2004     analyzeFlowExpressionNode(md, nametable, cn.getExpression(), nodeSet, base,
2005         implicitFlowTupleSet, false);
2006
2007   }
2008
2009   private void analyzeFlowTertiaryNode(MethodDescriptor md, SymbolTable nametable, TertiaryNode tn,
2010       NodeTupleSet nodeSet, NodeTupleSet implicitFlowTupleSet) {
2011
2012     NodeTupleSet tertiaryTupleNode = new NodeTupleSet();
2013     analyzeFlowExpressionNode(md, nametable, tn.getCond(), tertiaryTupleNode, null,
2014         implicitFlowTupleSet, false);
2015
2016     // add edges from tertiaryTupleNode to all nodes of conditional nodes
2017     tertiaryTupleNode.addTupleSet(implicitFlowTupleSet);
2018     analyzeFlowExpressionNode(md, nametable, tn.getTrueExpr(), tertiaryTupleNode, null,
2019         implicitFlowTupleSet, false);
2020
2021     analyzeFlowExpressionNode(md, nametable, tn.getFalseExpr(), tertiaryTupleNode, null,
2022         implicitFlowTupleSet, false);
2023
2024     nodeSet.addTupleSet(tertiaryTupleNode);
2025
2026   }
2027
2028   private void addMapCallerMethodDescToMethodInvokeNodeSet(MethodDescriptor caller,
2029       MethodInvokeNode min) {
2030     Set<MethodInvokeNode> set = mapMethodDescriptorToMethodInvokeNodeSet.get(caller);
2031     if (set == null) {
2032       set = new HashSet<MethodInvokeNode>();
2033       mapMethodDescriptorToMethodInvokeNodeSet.put(caller, set);
2034     }
2035     set.add(min);
2036   }
2037
2038   private void analyzeFlowMethodInvokeNode(MethodDescriptor md, SymbolTable nametable,
2039       MethodInvokeNode min, NodeTupleSet implicitFlowTupleSet) {
2040
2041     addMapCallerMethodDescToMethodInvokeNodeSet(md, min);
2042
2043     MethodDescriptor calleeMD = min.getMethod();
2044
2045     NameDescriptor baseName = min.getBaseName();
2046     boolean isSystemout = false;
2047     if (baseName != null) {
2048       isSystemout = baseName.getSymbol().equals("System.out");
2049     }
2050
2051     if (!ssjava.isSSJavaUtil(calleeMD.getClassDesc()) && !ssjava.isTrustMethod(calleeMD)
2052         && !calleeMD.getModifiers().isNative() && !isSystemout) {
2053
2054       // CompositeLocation baseLocation = null;
2055       if (min.getExpression() != null) {
2056
2057         NodeTupleSet baseNodeSet = new NodeTupleSet();
2058         analyzeFlowExpressionNode(md, nametable, min.getExpression(), baseNodeSet, null,
2059             implicitFlowTupleSet, false);
2060
2061       } else {
2062         if (min.getMethod().isStatic()) {
2063           // String globalLocId = ssjava.getMethodLattice(md).getGlobalLoc();
2064           // if (globalLocId == null) {
2065           // throw new
2066           // Error("Method lattice does not define global variable location at "
2067           // + generateErrorMessage(md.getClassDesc(), min));
2068           // }
2069           // baseLocation = new CompositeLocation(new Location(md,
2070           // globalLocId));
2071         } else {
2072           // 'this' var case
2073           // String thisLocId = ssjava.getMethodLattice(md).getThisLoc();
2074           // baseLocation = new CompositeLocation(new Location(md, thisLocId));
2075         }
2076       }
2077
2078       // constraint case:
2079       // if (constraint != null) {
2080       // int compareResult =
2081       // CompositeLattice.compare(constraint, baseLocation, true,
2082       // generateErrorMessage(cd, min));
2083       // if (compareResult != ComparisonResult.GREATER) {
2084       // // if the current constraint is higher than method's THIS location
2085       // // no need to check constraints!
2086       // CompositeLocation calleeConstraint =
2087       // translateCallerLocToCalleeLoc(calleeMD, baseLocation, constraint);
2088       // // System.out.println("check method body for constraint:" + calleeMD +
2089       // // " calleeConstraint="
2090       // // + calleeConstraint);
2091       // checkMethodBody(calleeMD.getClassDesc(), calleeMD, calleeConstraint);
2092       // }
2093       // }
2094
2095       analyzeFlowMethodParameters(md, nametable, min);
2096
2097       // checkCalleeConstraints(md, nametable, min, baseLocation, constraint);
2098
2099       // checkCallerArgumentLocationConstraints(md, nametable, min,
2100       // baseLocation, constraint);
2101
2102       if (min.getMethod().getReturnType() != null && !min.getMethod().getReturnType().isVoid()) {
2103         // If method has a return value, compute the highest possible return
2104         // location in the caller's perspective
2105         // CompositeLocation ceilingLoc =
2106         // computeCeilingLocationForCaller(md, nametable, min, baseLocation,
2107         // constraint);
2108         // return ceilingLoc;
2109       }
2110     }
2111
2112     // return new CompositeLocation(Location.createTopLocation(md));
2113
2114   }
2115
2116   private NodeTupleSet getNodeTupleSetByArgIdx(MethodInvokeNode min, int idx) {
2117     return mapMethodInvokeNodeToArgIdxMap.get(min).get(new Integer(idx));
2118   }
2119
2120   private void addArgIdxMap(MethodInvokeNode min, int idx, NodeTupleSet tupleSet) {
2121     Map<Integer, NodeTupleSet> mapIdxToTupleSet = mapMethodInvokeNodeToArgIdxMap.get(min);
2122     if (mapIdxToTupleSet == null) {
2123       mapIdxToTupleSet = new HashMap<Integer, NodeTupleSet>();
2124       mapMethodInvokeNodeToArgIdxMap.put(min, mapIdxToTupleSet);
2125     }
2126     mapIdxToTupleSet.put(new Integer(idx), tupleSet);
2127   }
2128
2129   private void analyzeFlowMethodParameters(MethodDescriptor callermd, SymbolTable nametable,
2130       MethodInvokeNode min) {
2131
2132     if (min.numArgs() > 0) {
2133
2134       int offset;
2135       if (min.getMethod().isStatic()) {
2136         offset = 0;
2137       } else {
2138         offset = 1;
2139         NTuple<Descriptor> thisArgTuple = new NTuple<Descriptor>();
2140         thisArgTuple.add(callermd.getThis());
2141         NodeTupleSet argTupleSet = new NodeTupleSet();
2142         argTupleSet.addTuple(thisArgTuple);
2143         addArgIdxMap(min, 0, argTupleSet);
2144       }
2145
2146       for (int i = 0; i < min.numArgs(); i++) {
2147         ExpressionNode en = min.getArg(i);
2148         NodeTupleSet argTupleSet = new NodeTupleSet();
2149         analyzeFlowExpressionNode(callermd, nametable, en, argTupleSet, false);
2150         // if argument is liternal node, argTuple is set to NULL.
2151         addArgIdxMap(min, i + offset, argTupleSet);
2152       }
2153
2154     }
2155
2156   }
2157
2158   private void analyzeLiteralNode(MethodDescriptor md, SymbolTable nametable, LiteralNode en) {
2159
2160   }
2161
2162   private void analyzeFlowArrayAccessNode(MethodDescriptor md, SymbolTable nametable,
2163       ArrayAccessNode aan, NodeTupleSet nodeSet, boolean isLHS) {
2164
2165     NodeTupleSet expNodeTupleSet = new NodeTupleSet();
2166     analyzeFlowExpressionNode(md, nametable, aan.getExpression(), expNodeTupleSet, isLHS);
2167
2168     NodeTupleSet idxNodeTupleSet = new NodeTupleSet();
2169     analyzeFlowExpressionNode(md, nametable, aan.getIndex(), idxNodeTupleSet, isLHS);
2170
2171     if (isLHS) {
2172       // need to create an edge from idx to array
2173       for (Iterator<NTuple<Descriptor>> idxIter = idxNodeTupleSet.iterator(); idxIter.hasNext();) {
2174         NTuple<Descriptor> idxTuple = idxIter.next();
2175         for (Iterator<NTuple<Descriptor>> arrIter = expNodeTupleSet.iterator(); arrIter.hasNext();) {
2176           NTuple<Descriptor> arrTuple = arrIter.next();
2177           getFlowGraph(md).addValueFlowEdge(idxTuple, arrTuple);
2178         }
2179       }
2180
2181       nodeSet.addTupleSet(expNodeTupleSet);
2182     } else {
2183       nodeSet.addTupleSet(expNodeTupleSet);
2184       nodeSet.addTupleSet(idxNodeTupleSet);
2185     }
2186   }
2187
2188   private void analyzeCreateObjectNode(MethodDescriptor md, SymbolTable nametable,
2189       CreateObjectNode en) {
2190     // TODO Auto-generated method stub
2191
2192   }
2193
2194   private void analyzeFlowOpNode(MethodDescriptor md, SymbolTable nametable, OpNode on,
2195       NodeTupleSet nodeSet, NodeTupleSet implicitFlowTupleSet) {
2196
2197     NodeTupleSet leftOpSet = new NodeTupleSet();
2198     NodeTupleSet rightOpSet = new NodeTupleSet();
2199
2200     // left operand
2201     analyzeFlowExpressionNode(md, nametable, on.getLeft(), leftOpSet, null, implicitFlowTupleSet,
2202         false);
2203
2204     if (on.getRight() != null) {
2205       // right operand
2206       analyzeFlowExpressionNode(md, nametable, on.getRight(), rightOpSet, null,
2207           implicitFlowTupleSet, false);
2208     }
2209
2210     Operation op = on.getOp();
2211
2212     switch (op.getOp()) {
2213
2214     case Operation.UNARYPLUS:
2215     case Operation.UNARYMINUS:
2216     case Operation.LOGIC_NOT:
2217       // single operand
2218       nodeSet.addTupleSet(leftOpSet);
2219       break;
2220
2221     case Operation.LOGIC_OR:
2222     case Operation.LOGIC_AND:
2223     case Operation.COMP:
2224     case Operation.BIT_OR:
2225     case Operation.BIT_XOR:
2226     case Operation.BIT_AND:
2227     case Operation.ISAVAILABLE:
2228     case Operation.EQUAL:
2229     case Operation.NOTEQUAL:
2230     case Operation.LT:
2231     case Operation.GT:
2232     case Operation.LTE:
2233     case Operation.GTE:
2234     case Operation.ADD:
2235     case Operation.SUB:
2236     case Operation.MULT:
2237     case Operation.DIV:
2238     case Operation.MOD:
2239     case Operation.LEFTSHIFT:
2240     case Operation.RIGHTSHIFT:
2241     case Operation.URIGHTSHIFT:
2242
2243       // there are two operands
2244       nodeSet.addTupleSet(leftOpSet);
2245       nodeSet.addTupleSet(rightOpSet);
2246       break;
2247
2248     default:
2249       throw new Error(op.toString());
2250     }
2251
2252   }
2253
2254   private NTuple<Descriptor> analyzeFlowNameNode(MethodDescriptor md, SymbolTable nametable,
2255       NameNode nn, NodeTupleSet nodeSet, NTuple<Descriptor> base, NodeTupleSet implicitFlowTupleSet) {
2256
2257     if (base == null) {
2258       base = new NTuple<Descriptor>();
2259     }
2260
2261     NameDescriptor nd = nn.getName();
2262
2263     if (nd.getBase() != null) {
2264       base =
2265           analyzeFlowExpressionNode(md, nametable, nn.getExpression(), nodeSet, base,
2266               implicitFlowTupleSet, false);
2267       if (base == null) {
2268         // base node has the top location
2269         return base;
2270       }
2271     } else {
2272       String varname = nd.toString();
2273       if (varname.equals("this")) {
2274         // 'this' itself!
2275         base.add(md.getThis());
2276         return base;
2277       }
2278
2279       Descriptor d = (Descriptor) nametable.get(varname);
2280
2281       if (d instanceof VarDescriptor) {
2282         VarDescriptor vd = (VarDescriptor) d;
2283         base.add(vd);
2284       } else if (d instanceof FieldDescriptor) {
2285         // the type of field descriptor has a location!
2286         FieldDescriptor fd = (FieldDescriptor) d;
2287         if (fd.isStatic()) {
2288           if (fd.isFinal()) {
2289             // if it is 'static final', no need to have flow node for the TOP
2290             // location
2291             return null;
2292           } else {
2293             // if 'static', assign the default GLOBAL LOCATION to the first
2294             // element of the tuple
2295             base.add(GLOBALDESC);
2296           }
2297         } else {
2298           // the location of field access starts from this, followed by field
2299           // location
2300           base.add(md.getThis());
2301         }
2302
2303         base.add(fd);
2304       } else if (d == null) {
2305         // access static field
2306         base.add(GLOBALDESC);
2307         // base.add(nn.getField());
2308         return base;
2309
2310         // FieldDescriptor fd = nn.getField();addFlowGraphEdge
2311         //
2312         // MethodLattice<String> localLattice = ssjava.getMethodLattice(md);
2313         // String globalLocId = localLattice.getGlobalLoc();
2314         // if (globalLocId == null) {
2315         // throw new
2316         // Error("Method lattice does not define global variable location at "
2317         // + generateErrorMessage(md.getClassDesc(), nn));
2318         // }
2319         // loc.addLocation(new Location(md, globalLocId));
2320         //
2321         // Location fieldLoc = (Location) fd.getType().getExtension();
2322         // loc.addLocation(fieldLoc);
2323         //
2324         // return loc;
2325
2326       }
2327     }
2328
2329     getFlowGraph(md).createNewFlowNode(base);
2330
2331     return base;
2332
2333   }
2334
2335   private NTuple<Descriptor> analyzeFlowFieldAccessNode(MethodDescriptor md, SymbolTable nametable,
2336       FieldAccessNode fan, NodeTupleSet nodeSet, NTuple<Descriptor> base,
2337       NodeTupleSet implicitFlowTupleSet, boolean isLHS) {
2338
2339     ExpressionNode left = fan.getExpression();
2340     TypeDescriptor ltd = left.getType();
2341     FieldDescriptor fd = fan.getField();
2342
2343     String varName = null;
2344     if (left.kind() == Kind.NameNode) {
2345       NameDescriptor nd = ((NameNode) left).getName();
2346       varName = nd.toString();
2347     }
2348
2349     if (ltd.isClassNameRef() || (varName != null && varName.equals("this"))) {
2350       // using a class name directly or access using this
2351       if (fd.isStatic() && fd.isFinal()) {
2352         return null;
2353       }
2354     }
2355
2356     NodeTupleSet idxNodeTupleSet = new NodeTupleSet();
2357     if (left instanceof ArrayAccessNode) {
2358
2359       ArrayAccessNode aan = (ArrayAccessNode) left;
2360       left = aan.getExpression();
2361       analyzeFlowExpressionNode(md, nametable, aan.getIndex(), idxNodeTupleSet, base,
2362           implicitFlowTupleSet, isLHS);
2363       nodeSet.addTupleSet(idxNodeTupleSet);
2364     }
2365     base =
2366         analyzeFlowExpressionNode(md, nametable, left, nodeSet, base, implicitFlowTupleSet, isLHS);
2367
2368     if (base == null) {
2369       // in this case, field is TOP location
2370       return null;
2371     } else {
2372
2373       NTuple<Descriptor> flowFieldTuple = new NTuple<Descriptor>(base.toList());
2374
2375       if (!left.getType().isPrimitive()) {
2376
2377         if (!fd.getSymbol().equals("length")) {
2378           // array.length access, just have the location of the array
2379           flowFieldTuple.add(fd);
2380           nodeSet.removeTuple(base);
2381         }
2382
2383       }
2384       getFlowGraph(md).createNewFlowNode(flowFieldTuple);
2385
2386       if (isLHS) {
2387         for (Iterator<NTuple<Descriptor>> idxIter = idxNodeTupleSet.iterator(); idxIter.hasNext();) {
2388           NTuple<Descriptor> idxTuple = idxIter.next();
2389           getFlowGraph(md).addValueFlowEdge(idxTuple, flowFieldTuple);
2390         }
2391       }
2392
2393       return flowFieldTuple;
2394
2395     }
2396
2397   }
2398
2399   private void debug_printTreeNode(TreeNode tn) {
2400
2401     System.out.println("DEBUG: " + tn.printNode(0) + "                line#=" + tn.getNumLine());
2402
2403   }
2404
2405   private void analyzeFlowAssignmentNode(MethodDescriptor md, SymbolTable nametable,
2406       AssignmentNode an, NodeTupleSet nodeSet, NTuple<Descriptor> base,
2407       NodeTupleSet implicitFlowTupleSet) {
2408
2409     NodeTupleSet nodeSetRHS = new NodeTupleSet();
2410     NodeTupleSet nodeSetLHS = new NodeTupleSet();
2411
2412     boolean postinc = true;
2413     if (an.getOperation().getBaseOp() == null
2414         || (an.getOperation().getBaseOp().getOp() != Operation.POSTINC && an.getOperation()
2415             .getBaseOp().getOp() != Operation.POSTDEC)) {
2416       postinc = false;
2417     }
2418     // if LHS is array access node, need to capture value flows between an array
2419     // and its index value
2420     analyzeFlowExpressionNode(md, nametable, an.getDest(), nodeSetLHS, null, implicitFlowTupleSet,
2421         true);
2422
2423     if (!postinc) {
2424       // analyze value flows of rhs expression
2425       analyzeFlowExpressionNode(md, nametable, an.getSrc(), nodeSetRHS, null, implicitFlowTupleSet,
2426           false);
2427
2428       // System.out.println("-analyzeFlowAssignmentNode=" + an.printNode(0));
2429       // System.out.println("-nodeSetLHS=" + nodeSetLHS);
2430       // System.out.println("-nodeSetRHS=" + nodeSetRHS);
2431       // System.out.println("-implicitFlowTupleSet=" + implicitFlowTupleSet);
2432       // System.out.println("-");
2433
2434       if (an.getOperation().getOp() >= 2 && an.getOperation().getOp() <= 12) {
2435         // if assignment contains OP+EQ operator, creates edges from LHS to LHS
2436         for (Iterator<NTuple<Descriptor>> iter = nodeSetLHS.iterator(); iter.hasNext();) {
2437           NTuple<Descriptor> fromTuple = iter.next();
2438           for (Iterator<NTuple<Descriptor>> iter2 = nodeSetLHS.iterator(); iter2.hasNext();) {
2439             NTuple<Descriptor> toTuple = iter2.next();
2440             addFlowGraphEdge(md, fromTuple, toTuple);
2441           }
2442         }
2443       }
2444
2445       // creates edges from RHS to LHS
2446       for (Iterator<NTuple<Descriptor>> iter = nodeSetRHS.iterator(); iter.hasNext();) {
2447         NTuple<Descriptor> fromTuple = iter.next();
2448         for (Iterator<NTuple<Descriptor>> iter2 = nodeSetLHS.iterator(); iter2.hasNext();) {
2449           NTuple<Descriptor> toTuple = iter2.next();
2450           addFlowGraphEdge(md, fromTuple, toTuple);
2451         }
2452       }
2453
2454       // creates edges from implicitFlowTupleSet to LHS
2455       for (Iterator<NTuple<Descriptor>> iter = implicitFlowTupleSet.iterator(); iter.hasNext();) {
2456         NTuple<Descriptor> fromTuple = iter.next();
2457         for (Iterator<NTuple<Descriptor>> iter2 = nodeSetLHS.iterator(); iter2.hasNext();) {
2458           NTuple<Descriptor> toTuple = iter2.next();
2459           addFlowGraphEdge(md, fromTuple, toTuple);
2460         }
2461       }
2462
2463     } else {
2464       // postinc case
2465       for (Iterator<NTuple<Descriptor>> iter2 = nodeSetLHS.iterator(); iter2.hasNext();) {
2466         NTuple<Descriptor> tuple = iter2.next();
2467         addFlowGraphEdge(md, tuple, tuple);
2468       }
2469
2470       // creates edges from implicitFlowTupleSet to LHS
2471       for (Iterator<NTuple<Descriptor>> iter = implicitFlowTupleSet.iterator(); iter.hasNext();) {
2472         NTuple<Descriptor> fromTuple = iter.next();
2473         for (Iterator<NTuple<Descriptor>> iter2 = nodeSetLHS.iterator(); iter2.hasNext();) {
2474           NTuple<Descriptor> toTuple = iter2.next();
2475           addFlowGraphEdge(md, fromTuple, toTuple);
2476         }
2477       }
2478
2479     }
2480
2481     if (nodeSet != null) {
2482       nodeSet.addTupleSet(nodeSetLHS);
2483     }
2484   }
2485
2486   public FlowGraph getFlowGraph(MethodDescriptor md) {
2487     return mapMethodDescriptorToFlowGraph.get(md);
2488   }
2489
2490   private boolean addFlowGraphEdge(MethodDescriptor md, NTuple<Descriptor> from,
2491       NTuple<Descriptor> to) {
2492     // TODO
2493     // return true if it adds a new edge
2494     FlowGraph graph = getFlowGraph(md);
2495     graph.addValueFlowEdge(from, to);
2496     return true;
2497   }
2498
2499   public void _debug_printGraph() {
2500     Set<MethodDescriptor> keySet = mapMethodDescriptorToFlowGraph.keySet();
2501
2502     for (Iterator<MethodDescriptor> iterator = keySet.iterator(); iterator.hasNext();) {
2503       MethodDescriptor md = (MethodDescriptor) iterator.next();
2504       FlowGraph fg = mapMethodDescriptorToFlowGraph.get(md);
2505       try {
2506         fg.writeGraph();
2507       } catch (IOException e) {
2508         e.printStackTrace();
2509       }
2510     }
2511
2512   }
2513
2514 }
2515
2516 class CyclicFlowException extends Exception {
2517
2518 }