implemented a fixed point based interprocedural analysis that analyzes flow-graphs...
[IRC.git] / Robust / src / Analysis / SSJava / LocationInference.java
1 package Analysis.SSJava;
2
3 import java.io.IOException;
4 import java.util.ArrayList;
5 import java.util.Collections;
6 import java.util.Comparator;
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.Iterator;
10 import java.util.LinkedList;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.Set;
14 import java.util.Stack;
15
16 import Analysis.SSJava.FlowDownCheck.ComparisonResult;
17 import Analysis.SSJava.FlowDownCheck.CompositeLattice;
18 import IR.ClassDescriptor;
19 import IR.Descriptor;
20 import IR.FieldDescriptor;
21 import IR.MethodDescriptor;
22 import IR.NameDescriptor;
23 import IR.Operation;
24 import IR.State;
25 import IR.SymbolTable;
26 import IR.TypeDescriptor;
27 import IR.VarDescriptor;
28 import IR.Flat.FlatMethod;
29 import IR.Tree.ArrayAccessNode;
30 import IR.Tree.AssignmentNode;
31 import IR.Tree.BlockExpressionNode;
32 import IR.Tree.BlockNode;
33 import IR.Tree.BlockStatementNode;
34 import IR.Tree.CastNode;
35 import IR.Tree.CreateObjectNode;
36 import IR.Tree.DeclarationNode;
37 import IR.Tree.ExpressionNode;
38 import IR.Tree.FieldAccessNode;
39 import IR.Tree.IfStatementNode;
40 import IR.Tree.Kind;
41 import IR.Tree.LiteralNode;
42 import IR.Tree.LoopNode;
43 import IR.Tree.MethodInvokeNode;
44 import IR.Tree.NameNode;
45 import IR.Tree.OpNode;
46 import IR.Tree.ReturnNode;
47 import IR.Tree.SubBlockNode;
48 import IR.Tree.SwitchStatementNode;
49 import IR.Tree.TertiaryNode;
50
51 public class LocationInference {
52
53   State state;
54   SSJavaAnalysis ssjava;
55
56   List<ClassDescriptor> toanalyzeList;
57   List<MethodDescriptor> toanalyzeMethodList;
58   Map<MethodDescriptor, FlowGraph> mapMethodDescriptorToFlowGraph;
59
60   // map a method descriptor to its set of parameter descriptors
61   Map<MethodDescriptor, Set<Descriptor>> mapMethodDescriptorToParamDescSet;
62
63   // keep current descriptors to visit in fixed-point interprocedural analysis,
64   private Stack<MethodDescriptor> methodDescriptorsToVisitStack;
65
66   // map a class descriptor to a field lattice
67   private Map<ClassDescriptor, SSJavaLattice<String>> cd2lattice;
68
69   // map a method descriptor to a method lattice
70   private Map<MethodDescriptor, SSJavaLattice<String>> md2lattice;
71
72   // map a method descriptor to a lattice mapping
73   private Map<MethodDescriptor, Map<VarDescriptor, String>> md2LatticeMapping;
74
75   // map a method descriptor to a lattice mapping
76   private Map<MethodDescriptor, Map<FieldDescriptor, String>> cd2LatticeMapping;
77
78   // map a method descriptor to the set of hierarchy relations that are
79   // contributed from the callee
80   private Map<MethodDescriptor, Set<ParamIndexRelation>> mapMethodDescriptorToCalleeParamRelationSet;
81
82   // map a method descriptor to the set of method invocation nodes which are
83   // invoked by the method descriptor
84   private Map<MethodDescriptor, Set<MethodInvokeNode>> mapMethodDescriptorToMethodInvokeNodeSet;
85
86   private Map<MethodInvokeNode, Map<Integer, NTuple<Descriptor>>> mapMethodInvokeNodeToArgIdxMap;
87
88   boolean debug = true;
89
90   public LocationInference(SSJavaAnalysis ssjava, State state) {
91     this.ssjava = ssjava;
92     this.state = state;
93     this.toanalyzeList = new ArrayList<ClassDescriptor>();
94     this.toanalyzeMethodList = new ArrayList<MethodDescriptor>();
95     this.mapMethodDescriptorToFlowGraph = new HashMap<MethodDescriptor, FlowGraph>();
96     this.cd2lattice = new HashMap<ClassDescriptor, SSJavaLattice<String>>();
97     this.md2lattice = new HashMap<MethodDescriptor, SSJavaLattice<String>>();
98     this.methodDescriptorsToVisitStack = new Stack<MethodDescriptor>();
99     this.md2LatticeMapping = new HashMap<MethodDescriptor, Map<VarDescriptor, String>>();
100     this.cd2LatticeMapping = new HashMap<MethodDescriptor, Map<FieldDescriptor, String>>();
101     this.mapMethodDescriptorToCalleeParamRelationSet =
102         new HashMap<MethodDescriptor, Set<ParamIndexRelation>>();
103     this.mapMethodDescriptorToMethodInvokeNodeSet =
104         new HashMap<MethodDescriptor, Set<MethodInvokeNode>>();
105     this.mapMethodInvokeNodeToArgIdxMap =
106         new HashMap<MethodInvokeNode, Map<Integer, NTuple<Descriptor>>>();
107
108   }
109
110   public void setupToAnalyze() {
111     SymbolTable classtable = state.getClassSymbolTable();
112     toanalyzeList.clear();
113     toanalyzeList.addAll(classtable.getValueSet());
114     Collections.sort(toanalyzeList, new Comparator<ClassDescriptor>() {
115       public int compare(ClassDescriptor o1, ClassDescriptor o2) {
116         return o1.getClassName().compareToIgnoreCase(o2.getClassName());
117       }
118     });
119   }
120
121   public void setupToAnalazeMethod(ClassDescriptor cd) {
122
123     SymbolTable methodtable = cd.getMethodTable();
124     toanalyzeMethodList.clear();
125     toanalyzeMethodList.addAll(methodtable.getValueSet());
126     Collections.sort(toanalyzeMethodList, new Comparator<MethodDescriptor>() {
127       public int compare(MethodDescriptor o1, MethodDescriptor o2) {
128         return o1.getSymbol().compareToIgnoreCase(o2.getSymbol());
129       }
130     });
131   }
132
133   public boolean toAnalyzeMethodIsEmpty() {
134     return toanalyzeMethodList.isEmpty();
135   }
136
137   public boolean toAnalyzeIsEmpty() {
138     return toanalyzeList.isEmpty();
139   }
140
141   public ClassDescriptor toAnalyzeNext() {
142     return toanalyzeList.remove(0);
143   }
144
145   public MethodDescriptor toAnalyzeMethodNext() {
146     return toanalyzeMethodList.remove(0);
147   }
148
149   public void inference() {
150
151     // 1) construct value flow graph
152     constructFlowGraph();
153
154     // 2) construct lattices
155     inferLattices();
156
157     debug_writeLatticeDotFile();
158
159   }
160
161   private void debug_writeLatticeDotFile() {
162     // generate lattice dot file
163
164     setupToAnalyze();
165
166     while (!toAnalyzeIsEmpty()) {
167       ClassDescriptor cd = toAnalyzeNext();
168
169       setupToAnalazeMethod(cd);
170
171       SSJavaLattice<String> classLattice = cd2lattice.get(cd);
172       if (classLattice != null) {
173         ssjava.writeLatticeDotFile(cd, null, classLattice);
174       }
175
176       while (!toAnalyzeMethodIsEmpty()) {
177         MethodDescriptor md = toAnalyzeMethodNext();
178         if (ssjava.needTobeAnnotated(md)) {
179           SSJavaLattice<String> methodLattice = md2lattice.get(md);
180           if (methodLattice != null) {
181             ssjava.writeLatticeDotFile(cd, md, methodLattice);
182           }
183         }
184       }
185     }
186
187   }
188
189   private void inferLattices() {
190
191     // do fixed-point analysis
192
193     // perform method READ/OVERWRITE analysis
194     LinkedList<MethodDescriptor> descriptorListToAnalyze = ssjava.getSortedDescriptors();
195
196     // current descriptors to visit in fixed-point interprocedural analysis,
197     // prioritized by
198     // dependency in the call graph
199     methodDescriptorsToVisitStack.clear();
200
201     descriptorListToAnalyze.removeFirst();
202
203     Set<MethodDescriptor> methodDescriptorToVistSet = new HashSet<MethodDescriptor>();
204     methodDescriptorToVistSet.addAll(descriptorListToAnalyze);
205
206     while (!descriptorListToAnalyze.isEmpty()) {
207       MethodDescriptor md = descriptorListToAnalyze.removeFirst();
208       methodDescriptorsToVisitStack.add(md);
209     }
210
211     // analyze scheduled methods until there are no more to visit
212     while (!methodDescriptorsToVisitStack.isEmpty()) {
213       // start to analyze leaf node
214       MethodDescriptor md = methodDescriptorsToVisitStack.pop();
215
216       SSJavaLattice<String> methodLattice =
217           new SSJavaLattice<String>(SSJavaLattice.TOP, SSJavaLattice.BOTTOM);
218
219       System.out.println();
220       System.out.println("SSJAVA: Inferencing the lattice from " + md);
221
222       analyzeMethodLattice(md, methodLattice);
223
224       SSJavaLattice<String> prevMethodLattice = getMethodLattice(md);
225
226       if (!methodLattice.equals(prevMethodLattice)) {
227         md2lattice.put(md, methodLattice);
228
229         // results for callee changed, so enqueue dependents caller for
230         // further analysis
231         Iterator<MethodDescriptor> depsItr = ssjava.getDependents(md).iterator();
232         while (depsItr.hasNext()) {
233           MethodDescriptor methodNext = depsItr.next();
234           if (!methodDescriptorsToVisitStack.contains(methodNext)
235               && methodDescriptorToVistSet.contains(methodNext)) {
236             methodDescriptorsToVisitStack.add(methodNext);
237           }
238         }
239
240       }
241
242     }
243
244   }
245
246   private String getSymbol(int idx, FlowNode node) {
247     Descriptor desc = node.getDescTuple().get(idx);
248     return desc.getSymbol();
249   }
250
251   private void analyzeMethodLattice(MethodDescriptor md, SSJavaLattice<String> methodLattice) {
252
253     // first take a look at method invocation nodes to newly added relations
254     // from the callee
255     analyzeLatticeMethodInvocationNode(md);
256
257     // visit each node of method flow graph
258
259     FlowGraph fg = getFlowGraph(md);
260     Set<FlowNode> nodeSet = fg.getNodeSet();
261
262     // for the method lattice, we need to look at the first element of
263     // NTuple<Descriptor>
264     for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
265       FlowNode srcNode = (FlowNode) iterator.next();
266
267       // first, take a look at directly connected nodes
268       Set<FlowEdge> outEdgeSet = srcNode.getOutEdgeSet();
269       for (Iterator iterator2 = outEdgeSet.iterator(); iterator2.hasNext();) {
270         FlowEdge outEdge = (FlowEdge) iterator2.next();
271         FlowNode dstNode = outEdge.getDst();
272
273         addRelationToLattice(md, methodLattice, srcNode, dstNode);
274
275       }
276
277     }
278
279   }
280
281   private void analyzeLatticeMethodInvocationNode(MethodDescriptor mdCaller) {
282
283     // the transformation for a call site propagates all relations between
284     // parameters from the callee
285     // if the method is virtual, it also grab all relations from any possible
286     // callees
287
288     Set<MethodInvokeNode> setMethodInvokeNode =
289         mapMethodDescriptorToMethodInvokeNodeSet.get(mdCaller);
290     if (setMethodInvokeNode != null) {
291
292       for (Iterator iterator = setMethodInvokeNode.iterator(); iterator.hasNext();) {
293         MethodInvokeNode min = (MethodInvokeNode) iterator.next();
294         MethodDescriptor mdCallee = min.getMethod();
295         Set<MethodDescriptor> setPossibleCallees = new HashSet<MethodDescriptor>();
296         if (mdCallee.isStatic()) {
297           setPossibleCallees.add(mdCallee);
298         } else {
299           setPossibleCallees.addAll(ssjava.getCallGraph().getMethods(mdCallee));
300         }
301
302         for (Iterator iterator2 = setPossibleCallees.iterator(); iterator2.hasNext();) {
303           MethodDescriptor possibleMdCallee = (MethodDescriptor) iterator2.next();
304           propagateRelationToCaller(min, mdCaller, possibleMdCallee);
305         }
306
307       }
308     }
309
310   }
311
312   private void propagateRelationToCaller(MethodInvokeNode min, MethodDescriptor mdCaller,
313       MethodDescriptor possibleMdCallee) {
314
315     SSJavaLattice<String> calleeLattice = getMethodLattice(possibleMdCallee);
316
317     FlowGraph calleeFlowGraph = getFlowGraph(possibleMdCallee);
318
319     // find parameter node
320     Set<FlowNode> paramNodeSet = calleeFlowGraph.getParameterNodeSet();
321
322     for (Iterator iterator = paramNodeSet.iterator(); iterator.hasNext();) {
323       FlowNode paramFlowNode1 = (FlowNode) iterator.next();
324
325       for (Iterator iterator2 = paramNodeSet.iterator(); iterator2.hasNext();) {
326         FlowNode paramFlowNode2 = (FlowNode) iterator2.next();
327
328         String paramSymbol1 = getSymbol(0, paramFlowNode1);
329         String paramSymbol2 = getSymbol(0, paramFlowNode2);
330         // if two parameters have relation, we need to propagate this relation
331         // to the caller
332         if (calleeLattice.isComparable(paramSymbol1, paramSymbol2)) {
333           int higherLocIdxCallee;
334           int lowerLocIdxCallee;
335           if (calleeLattice.isGreaterThan(paramSymbol1, paramSymbol2)) {
336             higherLocIdxCallee = calleeFlowGraph.getParamIdx(paramFlowNode1.getDescTuple());
337             lowerLocIdxCallee = calleeFlowGraph.getParamIdx(paramFlowNode2.getDescTuple());
338           } else {
339             higherLocIdxCallee = calleeFlowGraph.getParamIdx(paramFlowNode2.getDescTuple());
340             lowerLocIdxCallee = calleeFlowGraph.getParamIdx(paramFlowNode1.getDescTuple());
341           }
342
343           NTuple<Descriptor> higherArg = getArgTupleByArgIdx(min, higherLocIdxCallee);
344           NTuple<Descriptor> lowerArg = getArgTupleByArgIdx(min, lowerLocIdxCallee);
345
346           addFlowGraphEdge(mdCaller, higherArg, lowerArg);
347
348         }
349
350       }
351
352     }
353
354   }
355
356   private void addRelationToLattice(MethodDescriptor md, SSJavaLattice<String> methodLattice,
357       FlowNode srcNode, FlowNode dstNode) {
358     if ((srcNode.getDescTuple().size() > 1 && dstNode.getDescTuple().size() > 1)
359         && srcNode.getDescTuple().get(0).equals(dstNode.getDescTuple().get(0))) {
360       // value flow between fields: we don't need to add a binary relation
361       // for this case
362
363       VarDescriptor varDesc = (VarDescriptor) srcNode.getDescTuple().get(0);
364       ClassDescriptor varClassDesc = varDesc.getType().getClassDesc();
365
366       extractRelationFromFieldFlows(varClassDesc, srcNode, dstNode, 1);
367       return;
368     }
369
370     // add a new binary relation of dstNode < srcNode
371
372     String srcSymbol = getSymbol(0, srcNode);
373     String dstSymbol = getSymbol(0, dstNode);
374
375     methodLattice.addRelationHigherToLower(srcSymbol, dstSymbol);
376
377   }
378
379   private SSJavaLattice<String> getMethodLattice(MethodDescriptor md) {
380
381     if (!md2lattice.containsKey(md)) {
382       md2lattice.put(md, new SSJavaLattice<String>(SSJavaLattice.TOP, SSJavaLattice.BOTTOM));
383     }
384     return md2lattice.get(md);
385   }
386
387   private void extractRelationFromFieldFlows(ClassDescriptor cd, FlowNode srcNode,
388       FlowNode dstNode, int idx) {
389
390     if (srcNode.getDescTuple().get(idx).equals(dstNode.getDescTuple().get(idx))) {
391       // value flow between fields: we don't need to add a binary relation
392       // for this case
393       VarDescriptor varDesc = (VarDescriptor) srcNode.getDescTuple().get(idx);
394       ClassDescriptor varClassDesc = varDesc.getType().getClassDesc();
395       extractRelationFromFieldFlows(varClassDesc, srcNode, dstNode, idx + 1);
396     } else {
397
398       Descriptor srcFieldDesc = srcNode.getDescTuple().get(idx);
399       Descriptor dstFieldDesc = dstNode.getDescTuple().get(idx);
400
401       // add a new binary relation of dstNode < srcNode
402
403       SSJavaLattice<String> fieldLattice = getFieldLattice(cd);
404       fieldLattice.addRelationHigherToLower(srcFieldDesc.getSymbol(), dstFieldDesc.getSymbol());
405
406     }
407
408   }
409
410   public SSJavaLattice<String> getFieldLattice(ClassDescriptor cd) {
411     if (!cd2lattice.containsKey(cd)) {
412       cd2lattice.put(cd, new SSJavaLattice<String>(SSJavaLattice.TOP, SSJavaLattice.BOTTOM));
413     }
414     return cd2lattice.get(cd);
415   }
416
417   public void constructFlowGraph() {
418
419     setupToAnalyze();
420
421     while (!toAnalyzeIsEmpty()) {
422       ClassDescriptor cd = toAnalyzeNext();
423
424       setupToAnalazeMethod(cd);
425       while (!toAnalyzeMethodIsEmpty()) {
426         MethodDescriptor md = toAnalyzeMethodNext();
427         if (ssjava.needTobeAnnotated(md)) {
428           if (state.SSJAVADEBUG) {
429             System.out.println("SSJAVA: Constructing a flow graph: " + md);
430           }
431
432           // creates a mapping from a parameter descriptor to its index
433
434           Map<Descriptor, Integer> mapParamDescToIdx = new HashMap<Descriptor, Integer>();
435           int offset = md.isStatic() ? 0 : 1;
436           for (int i = 0; i < md.numParameters(); i++) {
437             Descriptor paramDesc = (Descriptor) md.getParameter(i);
438             mapParamDescToIdx.put(paramDesc, new Integer(i + offset));
439           }
440
441           FlowGraph fg = new FlowGraph(md, mapParamDescToIdx);
442           mapMethodDescriptorToFlowGraph.put(md, fg);
443
444           analyzeMethodBody(cd, md);
445         }
446       }
447     }
448
449     _debug_printGraph();
450   }
451
452   private void analyzeMethodBody(ClassDescriptor cd, MethodDescriptor md) {
453     BlockNode bn = state.getMethodBody(md);
454     NodeTupleSet implicitFlowTupleSet = new NodeTupleSet();
455     analyzeFlowBlockNode(md, md.getParameterTable(), bn, implicitFlowTupleSet);
456   }
457
458   private void analyzeFlowBlockNode(MethodDescriptor md, SymbolTable nametable, BlockNode bn,
459       NodeTupleSet implicitFlowTupleSet) {
460
461     bn.getVarTable().setParent(nametable);
462     for (int i = 0; i < bn.size(); i++) {
463       BlockStatementNode bsn = bn.get(i);
464       analyzeBlockStatementNode(md, bn.getVarTable(), bsn, implicitFlowTupleSet);
465     }
466
467   }
468
469   private void analyzeBlockStatementNode(MethodDescriptor md, SymbolTable nametable,
470       BlockStatementNode bsn, NodeTupleSet implicitFlowTupleSet) {
471
472     switch (bsn.kind()) {
473     case Kind.BlockExpressionNode:
474       analyzeBlockExpressionNode(md, nametable, (BlockExpressionNode) bsn, implicitFlowTupleSet);
475       break;
476
477     case Kind.DeclarationNode:
478       analyzeFlowDeclarationNode(md, nametable, (DeclarationNode) bsn, implicitFlowTupleSet);
479       break;
480
481     case Kind.IfStatementNode:
482       analyzeFlowIfStatementNode(md, nametable, (IfStatementNode) bsn, implicitFlowTupleSet);
483       break;
484
485     case Kind.LoopNode:
486       analyzeFlowLoopNode(md, nametable, (LoopNode) bsn, implicitFlowTupleSet);
487       break;
488
489     case Kind.ReturnNode:
490       analyzeReturnNode(md, nametable, (ReturnNode) bsn);
491       break;
492
493     case Kind.SubBlockNode:
494       analyzeFlowSubBlockNode(md, nametable, (SubBlockNode) bsn, implicitFlowTupleSet);
495       break;
496
497     case Kind.ContinueBreakNode:
498       break;
499
500     case Kind.SwitchStatementNode:
501       analyzeSwitchStatementNode(md, nametable, (SwitchStatementNode) bsn);
502       break;
503
504     }
505
506   }
507
508   private void analyzeSwitchStatementNode(MethodDescriptor md, SymbolTable nametable,
509       SwitchStatementNode bsn) {
510     // TODO Auto-generated method stub
511   }
512
513   private void analyzeFlowSubBlockNode(MethodDescriptor md, SymbolTable nametable,
514       SubBlockNode sbn, NodeTupleSet implicitFlowTupleSet) {
515     analyzeFlowBlockNode(md, nametable, sbn.getBlockNode(), implicitFlowTupleSet);
516   }
517
518   private void analyzeReturnNode(MethodDescriptor md, SymbolTable nametable, ReturnNode bsn) {
519     // TODO Auto-generated method stub
520
521   }
522
523   private void analyzeFlowLoopNode(MethodDescriptor md, SymbolTable nametable, LoopNode ln,
524       NodeTupleSet implicitFlowTupleSet) {
525
526     if (ln.getType() == LoopNode.WHILELOOP || ln.getType() == LoopNode.DOWHILELOOP) {
527
528       NodeTupleSet condTupleNode = new NodeTupleSet();
529       analyzeFlowExpressionNode(md, nametable, ln.getCondition(), condTupleNode, null,
530           implicitFlowTupleSet, false);
531       condTupleNode.addTupleSet(implicitFlowTupleSet);
532
533       // add edges from condNodeTupleSet to all nodes of conditional nodes
534       analyzeFlowBlockNode(md, nametable, ln.getBody(), condTupleNode);
535
536     } else {
537       // check 'for loop' case
538       BlockNode bn = ln.getInitializer();
539       analyzeFlowBlockNode(md, bn.getVarTable(), bn, implicitFlowTupleSet);
540       bn.getVarTable().setParent(nametable);
541
542       NodeTupleSet condTupleNode = new NodeTupleSet();
543       analyzeFlowExpressionNode(md, bn.getVarTable(), ln.getCondition(), condTupleNode, null,
544           implicitFlowTupleSet, false);
545       condTupleNode.addTupleSet(implicitFlowTupleSet);
546
547       analyzeFlowBlockNode(md, bn.getVarTable(), ln.getUpdate(), condTupleNode);
548       analyzeFlowBlockNode(md, bn.getVarTable(), ln.getBody(), condTupleNode);
549
550     }
551
552   }
553
554   private void analyzeFlowIfStatementNode(MethodDescriptor md, SymbolTable nametable,
555       IfStatementNode isn, NodeTupleSet implicitFlowTupleSet) {
556
557     NodeTupleSet condTupleNode = new NodeTupleSet();
558     analyzeFlowExpressionNode(md, nametable, isn.getCondition(), condTupleNode, null,
559         implicitFlowTupleSet, false);
560
561     // add edges from condNodeTupleSet to all nodes of conditional nodes
562     condTupleNode.addTupleSet(implicitFlowTupleSet);
563     analyzeFlowBlockNode(md, nametable, isn.getTrueBlock(), condTupleNode);
564
565     if (isn.getFalseBlock() != null) {
566       analyzeFlowBlockNode(md, nametable, isn.getFalseBlock(), condTupleNode);
567     }
568
569   }
570
571   private void analyzeFlowDeclarationNode(MethodDescriptor md, SymbolTable nametable,
572       DeclarationNode dn, NodeTupleSet implicitFlowTupleSet) {
573
574     VarDescriptor vd = dn.getVarDescriptor();
575     NTuple<Descriptor> tupleLHS = new NTuple<Descriptor>();
576     tupleLHS.add(vd);
577     getFlowGraph(md).createNewFlowNode(tupleLHS);
578
579     if (dn.getExpression() != null) {
580
581       NodeTupleSet tupleSetRHS = new NodeTupleSet();
582       analyzeFlowExpressionNode(md, nametable, dn.getExpression(), tupleSetRHS, null,
583           implicitFlowTupleSet, false);
584
585       // add a new flow edge from rhs to lhs
586       for (Iterator<NTuple<Descriptor>> iter = tupleSetRHS.iterator(); iter.hasNext();) {
587         NTuple<Descriptor> from = iter.next();
588         addFlowGraphEdge(md, from, tupleLHS);
589       }
590
591     }
592
593   }
594
595   private void analyzeBlockExpressionNode(MethodDescriptor md, SymbolTable nametable,
596       BlockExpressionNode ben, NodeTupleSet implicitFlowTupleSet) {
597     analyzeFlowExpressionNode(md, nametable, ben.getExpression(), null, null, implicitFlowTupleSet,
598         false);
599   }
600
601   private NTuple<Descriptor> analyzeFlowExpressionNode(MethodDescriptor md, SymbolTable nametable,
602       ExpressionNode en, NodeTupleSet nodeSet, boolean isLHS) {
603     return analyzeFlowExpressionNode(md, nametable, en, nodeSet, null, new NodeTupleSet(), isLHS);
604   }
605
606   private NTuple<Descriptor> analyzeFlowExpressionNode(MethodDescriptor md, SymbolTable nametable,
607       ExpressionNode en, NodeTupleSet nodeSet, NTuple<Descriptor> base,
608       NodeTupleSet implicitFlowTupleSet, boolean isLHS) {
609
610     // note that expression node can create more than one flow node
611     // nodeSet contains of flow nodes
612     // base is always assigned to null except name node case!
613
614     NTuple<Descriptor> flowTuple;
615
616     switch (en.kind()) {
617
618     case Kind.AssignmentNode:
619       analyzeFlowAssignmentNode(md, nametable, (AssignmentNode) en, base, implicitFlowTupleSet);
620       break;
621
622     case Kind.FieldAccessNode:
623       flowTuple =
624           analyzeFlowFieldAccessNode(md, nametable, (FieldAccessNode) en, nodeSet, base,
625               implicitFlowTupleSet);
626       nodeSet.addTuple(flowTuple);
627       return flowTuple;
628
629     case Kind.NameNode:
630       NodeTupleSet nameNodeSet = new NodeTupleSet();
631       flowTuple =
632           analyzeFlowNameNode(md, nametable, (NameNode) en, nameNodeSet, base, implicitFlowTupleSet);
633       nodeSet.addTuple(flowTuple);
634       return flowTuple;
635
636     case Kind.OpNode:
637       analyzeFlowOpNode(md, nametable, (OpNode) en, nodeSet, implicitFlowTupleSet);
638       break;
639
640     case Kind.CreateObjectNode:
641       analyzeCreateObjectNode(md, nametable, (CreateObjectNode) en);
642       break;
643
644     case Kind.ArrayAccessNode:
645       analyzeFlowArrayAccessNode(md, nametable, (ArrayAccessNode) en, nodeSet, isLHS);
646       break;
647
648     case Kind.LiteralNode:
649       analyzeLiteralNode(md, nametable, (LiteralNode) en);
650       break;
651
652     case Kind.MethodInvokeNode:
653       analyzeFlowMethodInvokeNode(md, nametable, (MethodInvokeNode) en, implicitFlowTupleSet);
654       break;
655
656     case Kind.TertiaryNode:
657       analyzeFlowTertiaryNode(md, nametable, (TertiaryNode) en, nodeSet, implicitFlowTupleSet);
658       break;
659
660     case Kind.CastNode:
661       analyzeFlowCastNode(md, nametable, (CastNode) en, implicitFlowTupleSet);
662       break;
663
664     // case Kind.InstanceOfNode:
665     // checkInstanceOfNode(md, nametable, (InstanceOfNode) en, td);
666     // return null;
667
668     // case Kind.ArrayInitializerNode:
669     // checkArrayInitializerNode(md, nametable, (ArrayInitializerNode) en,
670     // td);
671     // return null;
672
673     // case Kind.ClassTypeNode:
674     // checkClassTypeNode(md, nametable, (ClassTypeNode) en, td);
675     // return null;
676
677     // case Kind.OffsetNode:
678     // checkOffsetNode(md, nametable, (OffsetNode)en, td);
679     // return null;
680
681     }
682     return null;
683
684   }
685
686   private void analyzeFlowCastNode(MethodDescriptor md, SymbolTable nametable, CastNode cn,
687       NodeTupleSet implicitFlowTupleSet) {
688
689     NodeTupleSet nodeTupleSet = new NodeTupleSet();
690     analyzeFlowExpressionNode(md, nametable, cn.getExpression(), nodeTupleSet, false);
691
692   }
693
694   private void analyzeFlowTertiaryNode(MethodDescriptor md, SymbolTable nametable, TertiaryNode tn,
695       NodeTupleSet nodeSet, NodeTupleSet implicitFlowTupleSet) {
696
697     System.out.println("### analyzeFlowTertiaryNode=" + tn.printNode(0));
698
699     NodeTupleSet tertiaryTupleNode = new NodeTupleSet();
700     analyzeFlowExpressionNode(md, nametable, tn.getCond(), tertiaryTupleNode, null,
701         implicitFlowTupleSet, false);
702
703     // add edges from tertiaryTupleNode to all nodes of conditional nodes
704     tertiaryTupleNode.addTupleSet(implicitFlowTupleSet);
705     System.out.println("### TertiarayNode's condition=" + tertiaryTupleNode);
706     analyzeFlowExpressionNode(md, nametable, tn.getTrueExpr(), tertiaryTupleNode, null,
707         implicitFlowTupleSet, false);
708
709     analyzeFlowExpressionNode(md, nametable, tn.getFalseExpr(), tertiaryTupleNode, null,
710         implicitFlowTupleSet, false);
711
712     nodeSet.addTupleSet(tertiaryTupleNode);
713
714   }
715
716   private void addMapCallerMethodDescToMethodInvokeNodeSet(MethodDescriptor caller,
717       MethodInvokeNode min) {
718     Set<MethodInvokeNode> set = mapMethodDescriptorToMethodInvokeNodeSet.get(caller);
719     if (set == null) {
720       set = new HashSet<MethodInvokeNode>();
721       mapMethodDescriptorToMethodInvokeNodeSet.put(caller, set);
722     }
723     set.add(min);
724   }
725
726   private void analyzeFlowMethodInvokeNode(MethodDescriptor md, SymbolTable nametable,
727       MethodInvokeNode min, NodeTupleSet implicitFlowTupleSet) {
728
729     addMapCallerMethodDescToMethodInvokeNodeSet(md, min);
730
731     MethodDescriptor calleeMD = min.getMethod();
732
733     NameDescriptor baseName = min.getBaseName();
734     boolean isSystemout = false;
735     if (baseName != null) {
736       isSystemout = baseName.getSymbol().equals("System.out");
737     }
738
739     if (!ssjava.isSSJavaUtil(calleeMD.getClassDesc()) && !ssjava.isTrustMethod(calleeMD)
740         && !calleeMD.getModifiers().isNative() && !isSystemout) {
741
742       // CompositeLocation baseLocation = null;
743       if (min.getExpression() != null) {
744
745         NodeTupleSet baseNodeSet = new NodeTupleSet();
746         System.out.println("Analyzing base of method=" + min.getExpression());
747         analyzeFlowExpressionNode(calleeMD, nametable, min.getExpression(), baseNodeSet, null,
748             implicitFlowTupleSet, false);
749
750       } else {
751         if (min.getMethod().isStatic()) {
752           // String globalLocId = ssjava.getMethodLattice(md).getGlobalLoc();
753           // if (globalLocId == null) {
754           // throw new
755           // Error("Method lattice does not define global variable location at "
756           // + generateErrorMessage(md.getClassDesc(), min));
757           // }
758           // baseLocation = new CompositeLocation(new Location(md,
759           // globalLocId));
760         } else {
761           // 'this' var case
762           // String thisLocId = ssjava.getMethodLattice(md).getThisLoc();
763           // baseLocation = new CompositeLocation(new Location(md, thisLocId));
764         }
765       }
766
767       // constraint case:
768       // if (constraint != null) {
769       // int compareResult =
770       // CompositeLattice.compare(constraint, baseLocation, true,
771       // generateErrorMessage(cd, min));
772       // if (compareResult != ComparisonResult.GREATER) {
773       // // if the current constraint is higher than method's THIS location
774       // // no need to check constraints!
775       // CompositeLocation calleeConstraint =
776       // translateCallerLocToCalleeLoc(calleeMD, baseLocation, constraint);
777       // // System.out.println("check method body for constraint:" + calleeMD +
778       // // " calleeConstraint="
779       // // + calleeConstraint);
780       // checkMethodBody(calleeMD.getClassDesc(), calleeMD, calleeConstraint);
781       // }
782       // }
783
784       analyzeFlowMethodParameters(md, nametable, min);
785
786       // checkCalleeConstraints(md, nametable, min, baseLocation, constraint);
787
788       // checkCallerArgumentLocationConstraints(md, nametable, min,
789       // baseLocation, constraint);
790
791       if (!min.getMethod().getReturnType().isVoid()) {
792         // If method has a return value, compute the highest possible return
793         // location in the caller's perspective
794         // CompositeLocation ceilingLoc =
795         // computeCeilingLocationForCaller(md, nametable, min, baseLocation,
796         // constraint);
797         // return ceilingLoc;
798       }
799     }
800
801     // return new CompositeLocation(Location.createTopLocation(md));
802
803   }
804
805   private NTuple<Descriptor> getArgTupleByArgIdx(MethodInvokeNode min, int idx) {
806     return mapMethodInvokeNodeToArgIdxMap.get(min).get(new Integer(idx));
807   }
808
809   private void addArgIdxMap(MethodInvokeNode min, int idx, NTuple<Descriptor> argTuple) {
810     Map<Integer, NTuple<Descriptor>> mapIdxToArgTuple = mapMethodInvokeNodeToArgIdxMap.get(min);
811     if (mapIdxToArgTuple == null) {
812       mapIdxToArgTuple = new HashMap<Integer, NTuple<Descriptor>>();
813       mapMethodInvokeNodeToArgIdxMap.put(min, mapIdxToArgTuple);
814     }
815     mapIdxToArgTuple.put(new Integer(idx), argTuple);
816   }
817
818   private void analyzeFlowMethodParameters(MethodDescriptor callermd, SymbolTable nametable,
819       MethodInvokeNode min) {
820
821     if (min.numArgs() > 0) {
822
823       int offset = min.getMethod().isStatic() ? 0 : 1;
824
825       for (int i = 0; i < min.numArgs(); i++) {
826         ExpressionNode en = min.getArg(i);
827         NTuple<Descriptor> argTuple =
828             analyzeFlowExpressionNode(callermd, nametable, en, new NodeTupleSet(), false);
829
830         addArgIdxMap(min, i + offset, argTuple);
831       }
832
833     }
834
835   }
836
837   private void analyzeLiteralNode(MethodDescriptor md, SymbolTable nametable, LiteralNode en) {
838     // TODO Auto-generated method stub
839
840   }
841
842   private void analyzeFlowArrayAccessNode(MethodDescriptor md, SymbolTable nametable,
843       ArrayAccessNode aan, NodeTupleSet nodeSet, boolean isLHS) {
844
845     NodeTupleSet expNodeTupleSet = new NodeTupleSet();
846     analyzeFlowExpressionNode(md, nametable, aan.getExpression(), expNodeTupleSet, isLHS);
847
848     NodeTupleSet idxNodeTupleSet = new NodeTupleSet();
849     analyzeFlowExpressionNode(md, nametable, aan.getIndex(), idxNodeTupleSet, isLHS);
850
851     if (isLHS) {
852       // need to create an edge from idx to array
853
854       for (Iterator<NTuple<Descriptor>> idxIter = idxNodeTupleSet.iterator(); idxIter.hasNext();) {
855         NTuple<Descriptor> idxTuple = idxIter.next();
856         for (Iterator<NTuple<Descriptor>> arrIter = expNodeTupleSet.iterator(); arrIter.hasNext();) {
857           NTuple<Descriptor> arrTuple = arrIter.next();
858           getFlowGraph(md).addValueFlowEdge(idxTuple, arrTuple);
859         }
860       }
861
862       nodeSet.addTupleSet(expNodeTupleSet);
863     } else {
864       nodeSet.addTupleSet(expNodeTupleSet);
865       nodeSet.addTupleSet(idxNodeTupleSet);
866     }
867
868   }
869
870   private void analyzeCreateObjectNode(MethodDescriptor md, SymbolTable nametable,
871       CreateObjectNode en) {
872     // TODO Auto-generated method stub
873
874   }
875
876   private void analyzeFlowOpNode(MethodDescriptor md, SymbolTable nametable, OpNode on,
877       NodeTupleSet nodeSet, NodeTupleSet implicitFlowTupleSet) {
878
879     NodeTupleSet leftOpSet = new NodeTupleSet();
880     NodeTupleSet rightOpSet = new NodeTupleSet();
881
882     // left operand
883     System.out.println("Analyzing left op=" + on.getLeft().printNode(0) + "::"
884         + on.getLeft().getClass());
885     analyzeFlowExpressionNode(md, nametable, on.getLeft(), leftOpSet, null, implicitFlowTupleSet,
886         false);
887     System.out.println("leftOpSet=" + leftOpSet);
888
889     if (on.getRight() != null) {
890       // right operand
891       analyzeFlowExpressionNode(md, nametable, on.getRight(), rightOpSet, null,
892           implicitFlowTupleSet, false);
893       System.out.println("rightOpSet=" + rightOpSet);
894     }
895
896     Operation op = on.getOp();
897
898     switch (op.getOp()) {
899
900     case Operation.UNARYPLUS:
901     case Operation.UNARYMINUS:
902     case Operation.LOGIC_NOT:
903       // single operand
904       nodeSet.addTupleSet(leftOpSet);
905       break;
906
907     case Operation.LOGIC_OR:
908     case Operation.LOGIC_AND:
909     case Operation.COMP:
910     case Operation.BIT_OR:
911     case Operation.BIT_XOR:
912     case Operation.BIT_AND:
913     case Operation.ISAVAILABLE:
914     case Operation.EQUAL:
915     case Operation.NOTEQUAL:
916     case Operation.LT:
917     case Operation.GT:
918     case Operation.LTE:
919     case Operation.GTE:
920     case Operation.ADD:
921     case Operation.SUB:
922     case Operation.MULT:
923     case Operation.DIV:
924     case Operation.MOD:
925     case Operation.LEFTSHIFT:
926     case Operation.RIGHTSHIFT:
927     case Operation.URIGHTSHIFT:
928
929       // there are two operands
930       nodeSet.addTupleSet(leftOpSet);
931       nodeSet.addTupleSet(rightOpSet);
932       break;
933
934     default:
935       throw new Error(op.toString());
936     }
937   }
938
939   private NTuple<Descriptor> analyzeFlowNameNode(MethodDescriptor md, SymbolTable nametable,
940       NameNode nn, NodeTupleSet nodeSet, NTuple<Descriptor> base, NodeTupleSet implicitFlowTupleSet) {
941
942     if (base == null) {
943       base = new NTuple<Descriptor>();
944     }
945
946     NameDescriptor nd = nn.getName();
947
948     if (nd.getBase() != null) {
949       analyzeFlowExpressionNode(md, nametable, nn.getExpression(), nodeSet, base,
950           implicitFlowTupleSet, false);
951     } else {
952       String varname = nd.toString();
953       if (varname.equals("this")) {
954         // 'this' itself!
955         base.add(md.getThis());
956         return base;
957       }
958
959       Descriptor d = (Descriptor) nametable.get(varname);
960
961       if (d instanceof VarDescriptor) {
962         VarDescriptor vd = (VarDescriptor) d;
963         base.add(vd);
964       } else if (d instanceof FieldDescriptor) {
965         // the type of field descriptor has a location!
966         FieldDescriptor fd = (FieldDescriptor) d;
967         if (fd.isStatic()) {
968           if (fd.isFinal()) {
969             // if it is 'static final', the location has TOP since no one can
970             // change its value
971             // loc.addLocation(Location.createTopLocation(md));
972             // return loc;
973           } else {
974             // if 'static', the location has pre-assigned global loc
975             // MethodLattice<String> localLattice = ssjava.getMethodLattice(md);
976             // String globalLocId = localLattice.getGlobalLoc();
977             // if (globalLocId == null) {
978             // throw new
979             // Error("Global location element is not defined in the method " +
980             // md);
981             // }
982             // Location globalLoc = new Location(md, globalLocId);
983             //
984             // loc.addLocation(globalLoc);
985           }
986         } else {
987           // the location of field access starts from this, followed by field
988           // location
989           base.add(md.getThis());
990         }
991
992         base.add(fd);
993       } else if (d == null) {
994         // access static field
995         // FieldDescriptor fd = nn.getField();addFlowGraphEdge
996         //
997         // MethodLattice<String> localLattice = ssjava.getMethodLattice(md);
998         // String globalLocId = localLattice.getGlobalLoc();
999         // if (globalLocId == null) {
1000         // throw new
1001         // Error("Method lattice does not define global variable location at "
1002         // + generateErrorMessage(md.getClassDesc(), nn));
1003         // }
1004         // loc.addLocation(new Location(md, globalLocId));
1005         //
1006         // Location fieldLoc = (Location) fd.getType().getExtension();
1007         // loc.addLocation(fieldLoc);
1008         //
1009         // return loc;
1010
1011       }
1012     }
1013
1014     getFlowGraph(md).createNewFlowNode(base);
1015
1016     return base;
1017
1018   }
1019
1020   private NTuple<Descriptor> analyzeFlowFieldAccessNode(MethodDescriptor md, SymbolTable nametable,
1021       FieldAccessNode fan, NodeTupleSet nodeSet, NTuple<Descriptor> base,
1022       NodeTupleSet implicitFlowTupleSet) {
1023
1024     ExpressionNode left = fan.getExpression();
1025     TypeDescriptor ltd = left.getType();
1026     FieldDescriptor fd = fan.getField();
1027
1028     String varName = null;
1029     if (left.kind() == Kind.NameNode) {
1030       NameDescriptor nd = ((NameNode) left).getName();
1031       varName = nd.toString();
1032     }
1033
1034     if (ltd.isClassNameRef() || (varName != null && varName.equals("this"))) {
1035       // using a class name directly or access using this
1036       if (fd.isStatic() && fd.isFinal()) {
1037         // loc.addLocation(Location.createTopLocation(md));
1038         // return loc;
1039       }
1040     }
1041
1042     // if (left instanceof ArrayAccessNode) {
1043     // ArrayAccessNode aan = (ArrayAccessNode) left;
1044     // left = aan.getExpression();
1045     // }
1046     // fanNodeSet
1047     base =
1048         analyzeFlowExpressionNode(md, nametable, left, nodeSet, base, implicitFlowTupleSet, false);
1049
1050     if (!left.getType().isPrimitive()) {
1051
1052       if (fd.getSymbol().equals("length")) {
1053         // TODO
1054         // array.length access, return the location of the array
1055         // return loc;
1056       }
1057
1058       base.add(fd);
1059     }
1060
1061     return base;
1062
1063   }
1064
1065   private void analyzeFlowAssignmentNode(MethodDescriptor md, SymbolTable nametable,
1066       AssignmentNode an, NTuple<Descriptor> base, NodeTupleSet implicitFlowTupleSet) {
1067
1068     System.out.println("analyzeFlowAssignmentNode=" + an);
1069
1070     NodeTupleSet nodeSetRHS = new NodeTupleSet();
1071     NodeTupleSet nodeSetLHS = new NodeTupleSet();
1072
1073     boolean postinc = true;
1074     if (an.getOperation().getBaseOp() == null
1075         || (an.getOperation().getBaseOp().getOp() != Operation.POSTINC && an.getOperation()
1076             .getBaseOp().getOp() != Operation.POSTDEC)) {
1077       postinc = false;
1078     }
1079
1080     // if LHS is array access node, need to capture value flows between an array
1081     // and its index value
1082     analyzeFlowExpressionNode(md, nametable, an.getDest(), nodeSetLHS, null, implicitFlowTupleSet,
1083         true);
1084     System.out.println("ASSIGNMENT NODE nodeSetLHS=" + nodeSetLHS);
1085
1086     if (!postinc) {
1087       // analyze value flows of rhs expression
1088       analyzeFlowExpressionNode(md, nametable, an.getSrc(), nodeSetRHS, null, implicitFlowTupleSet,
1089           false);
1090       System.out.println("ASSIGNMENT NODE nodeSetRHS=" + nodeSetRHS);
1091
1092       // creates edges from RHS to LHS
1093       for (Iterator<NTuple<Descriptor>> iter = nodeSetRHS.iterator(); iter.hasNext();) {
1094         NTuple<Descriptor> fromTuple = iter.next();
1095         for (Iterator<NTuple<Descriptor>> iter2 = nodeSetLHS.iterator(); iter2.hasNext();) {
1096           NTuple<Descriptor> toTuple = iter2.next();
1097           addFlowGraphEdge(md, fromTuple, toTuple);
1098         }
1099       }
1100
1101       // creates edges from implicitFlowTupleSet to LHS
1102       for (Iterator<NTuple<Descriptor>> iter = implicitFlowTupleSet.iterator(); iter.hasNext();) {
1103         NTuple<Descriptor> fromTuple = iter.next();
1104         for (Iterator<NTuple<Descriptor>> iter2 = nodeSetLHS.iterator(); iter2.hasNext();) {
1105           NTuple<Descriptor> toTuple = iter2.next();
1106           addFlowGraphEdge(md, fromTuple, toTuple);
1107         }
1108       }
1109
1110     } else {
1111       // postinc case
1112       for (Iterator<NTuple<Descriptor>> iter2 = nodeSetLHS.iterator(); iter2.hasNext();) {
1113         NTuple<Descriptor> tuple = iter2.next();
1114         addFlowGraphEdge(md, tuple, tuple);
1115       }
1116
1117     }
1118
1119   }
1120
1121   public FlowGraph getFlowGraph(MethodDescriptor md) {
1122     return mapMethodDescriptorToFlowGraph.get(md);
1123   }
1124
1125   public boolean addFlowGraphEdge(MethodDescriptor md, NTuple<Descriptor> from,
1126       NTuple<Descriptor> to) {
1127     // TODO
1128     // return true if it adds a new edge
1129     FlowGraph graph = getFlowGraph(md);
1130     graph.addValueFlowEdge(from, to);
1131     return true;
1132   }
1133
1134   public void _debug_printGraph() {
1135     Set<MethodDescriptor> keySet = mapMethodDescriptorToFlowGraph.keySet();
1136
1137     for (Iterator<MethodDescriptor> iterator = keySet.iterator(); iterator.hasNext();) {
1138       MethodDescriptor md = (MethodDescriptor) iterator.next();
1139       FlowGraph fg = mapMethodDescriptorToFlowGraph.get(md);
1140       try {
1141         fg.writeGraph();
1142       } catch (IOException e) {
1143         e.printStackTrace();
1144       }
1145     }
1146
1147   }
1148
1149 }
1150
1151 class ParamIndexRelation {
1152   private Integer higherIdx;
1153   private Integer lowerIdx;
1154 }