more implementation for the inference: propagating relations of callee parameters...
[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, 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, 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       FlatMethod fm = state.getMethodFlat(md);
216
217       SSJavaLattice<String> methodLattice =
218           new SSJavaLattice<String>(SSJavaLattice.TOP, SSJavaLattice.BOTTOM);
219
220       System.out.println("SSJAVA: Inferencing the lattice from " + md);
221
222       analyzeMethodLattice(md, methodLattice);
223
224       SSJavaLattice<String> prevMethodLattice = md2lattice.get(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 addMappingDescriptorToLocationIdentifer(MethodDescriptor methodDesc,
252       VarDescriptor varDesc, String identifier) {
253     if (!md2LatticeMapping.containsKey(methodDesc)) {
254       md2LatticeMapping.put(methodDesc, new HashMap<VarDescriptor, String>());
255     }
256
257   }
258
259   private void analyzeMethodLattice(MethodDescriptor md, SSJavaLattice<String> methodLattice) {
260
261     // visit each node of method flow graph
262
263     FlowGraph fg = getFlowGraph(md);
264     Set<FlowNode> nodeSet = fg.getNodeSet();
265
266     // for the method lattice, we need to look at the first element of
267     // NTuple<Descriptor>
268
269     for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
270       FlowNode srcNode = (FlowNode) iterator.next();
271
272       // first, take a look at directly connected nodes
273       Set<FlowEdge> outEdgeSet = srcNode.getOutEdgeSet();
274       for (Iterator iterator2 = outEdgeSet.iterator(); iterator2.hasNext();) {
275         FlowEdge outEdge = (FlowEdge) iterator2.next();
276         FlowNode dstNode = outEdge.getDst();
277
278         addRelationToLattice(md, methodLattice, srcNode, dstNode);
279
280         // second, take a look at all nodes that are reachable from the source
281         // node
282         recursiveVisitNodes(md, srcNode, dstNode);
283
284       }
285
286     }
287
288   }
289
290   private void addRelationToLattice(MethodDescriptor md, SSJavaLattice<String> methodLattice,
291       FlowNode srcNode, FlowNode dstNode) {
292     if ((srcNode.getDescTuple().size() > 1 && dstNode.getDescTuple().size() > 1)
293         && srcNode.getDescTuple().get(0).equals(dstNode.getDescTuple().get(0))) {
294       // value flow between fields: we don't need to add a binary relation
295       // for this case
296
297       VarDescriptor varDesc = (VarDescriptor) srcNode.getDescTuple().get(0);
298       ClassDescriptor varClassDesc = varDesc.getType().getClassDesc();
299
300       extractRelationFromFieldFlows(varClassDesc, srcNode, dstNode, 1);
301       return;
302     }
303
304     // add a new binary relation of dstNode < srcNode
305
306     String srcSymbol = getSymbol(0, srcNode);
307     String dstSymbol = getSymbol(0, dstNode);
308
309     methodLattice.addRelationHigherToLower(srcSymbol, dstSymbol);
310
311     if (srcNode.isParameter() && dstNode.isParameter()) {
312       propagateRelationToCaller(md, srcNode, dstNode);
313     }
314   }
315
316   private SSJavaLattice<String> getMethodLattice(MethodDescriptor md) {
317
318     if (!md2lattice.containsKey(md)) {
319       md2lattice.put(md, new SSJavaLattice<String>(SSJavaLattice.TOP, SSJavaLattice.BOTTOM));
320     }
321     return md2lattice.get(md);
322   }
323
324   private void propagateRelationToCaller(MethodDescriptor calleeMethodDesc, FlowNode srcNode,
325       FlowNode newVisitNode) {
326
327     FlowGraph calleeFlowGraph = getFlowGraph(calleeMethodDesc);
328
329     int higherLocIdxCallee = calleeFlowGraph.getParamIdx(srcNode.getDescTuple());
330     int lowerLocIdxCallee = calleeFlowGraph.getParamIdx(newVisitNode.getDescTuple());
331
332     System.out.println(" ssjava.getDependents(md)=" + ssjava.getDependents(calleeMethodDesc));
333     Iterator<MethodDescriptor> depsItr = ssjava.getDependents(calleeMethodDesc).iterator();
334     while (depsItr.hasNext()) {
335       MethodDescriptor callerMethodDesc = depsItr.next();
336
337       SSJavaLattice<String> callerMethodLattice = md2lattice.get(callerMethodDesc);
338
339       Set<MethodInvokeNode> minSet = mapMethodDescriptorToMethodInvokeNodeSet.get(callerMethodDesc);
340       for (Iterator iterator = minSet.iterator(); iterator.hasNext();) {
341         MethodInvokeNode methodInvokeNode = (MethodInvokeNode) iterator.next();
342         if (methodInvokeNode.getMethod().equals(calleeMethodDesc)) {
343           // need to propagate a relation from the callee to the caller
344           // TODO
345
346           System.out.println("higherLocIdxCallee=" + higherLocIdxCallee);
347           System.out.println("lowerLocIdxCallee=" + lowerLocIdxCallee);
348
349           NTuple<Descriptor> higherArg = getArgTupleByArgIdx(methodInvokeNode, higherLocIdxCallee);
350           NTuple<Descriptor> lowerArg = getArgTupleByArgIdx(methodInvokeNode, lowerLocIdxCallee);
351
352           FlowNode callerHigherFlowNode = getFlowGraph(callerMethodDesc).getFlowNode(higherArg);
353           FlowNode calleeHigherFlowNode = getFlowGraph(callerMethodDesc).getFlowNode(lowerArg);
354
355           addRelationToLattice(callerMethodDesc, getMethodLattice(callerMethodDesc),
356               callerHigherFlowNode, calleeHigherFlowNode);
357
358         }
359       }
360
361     }
362   }
363
364   private void recursiveVisitNodes(MethodDescriptor md, FlowNode srcNode, FlowNode currentVisitNode) {
365
366     NTuple<Descriptor> srcTuple = srcNode.getDescTuple();
367
368     for (Iterator<FlowEdge> outEdgeIter = currentVisitNode.getOutEdgeSet().iterator(); outEdgeIter
369         .hasNext();) {
370
371       FlowEdge outEdge = outEdgeIter.next();
372       FlowNode newVisitNode = outEdge.getDst();
373
374       NTuple<Descriptor> newVisitTuple = newVisitNode.getDescTuple();
375
376       // if both the source node and the newly visit node are parameters,
377       // need to keep this relation, then later add a new relation between
378       // corresponding arguments in the caller's lattice.
379       if (srcNode.isParameter() && newVisitNode.isParameter()) {
380         System.out.println("src=" + srcNode + "            newVisitNode=" + newVisitNode);
381         propagateRelationToCaller(md, srcNode, newVisitNode);
382       }
383
384     }
385
386   }
387
388   private void extractRelationFromFieldFlows(ClassDescriptor cd, FlowNode srcNode,
389       FlowNode dstNode, int idx) {
390
391     if (srcNode.getDescTuple().get(idx).equals(dstNode.getDescTuple().get(idx))) {
392       // value flow between fields: we don't need to add a binary relation
393       // for this case
394       VarDescriptor varDesc = (VarDescriptor) srcNode.getDescTuple().get(idx);
395       ClassDescriptor varClassDesc = varDesc.getType().getClassDesc();
396       extractRelationFromFieldFlows(varClassDesc, srcNode, dstNode, idx + 1);
397     } else {
398
399       Descriptor srcFieldDesc = srcNode.getDescTuple().get(idx);
400       Descriptor dstFieldDesc = dstNode.getDescTuple().get(idx);
401
402       // add a new binary relation of dstNode < srcNode
403
404       SSJavaLattice<String> fieldLattice = getFieldLattice(cd);
405       fieldLattice.addRelationHigherToLower(srcFieldDesc.getSymbol(), dstFieldDesc.getSymbol());
406
407     }
408
409   }
410
411   public SSJavaLattice<String> getFieldLattice(ClassDescriptor cd) {
412     if (!cd2lattice.containsKey(cd)) {
413       cd2lattice.put(cd, new SSJavaLattice<String>(SSJavaLattice.TOP, SSJavaLattice.BOTTOM));
414     }
415     return cd2lattice.get(cd);
416   }
417
418   public void constructFlowGraph() {
419
420     setupToAnalyze();
421
422     while (!toAnalyzeIsEmpty()) {
423       ClassDescriptor cd = toAnalyzeNext();
424
425       setupToAnalazeMethod(cd);
426       while (!toAnalyzeMethodIsEmpty()) {
427         MethodDescriptor md = toAnalyzeMethodNext();
428         if (ssjava.needTobeAnnotated(md)) {
429           if (state.SSJAVADEBUG) {
430             System.out.println("SSJAVA: Constructing a flow graph: " + md);
431           }
432
433           // creates a mapping from a parameter descriptor to its index
434
435           Map<Descriptor, Integer> mapParamDescToIdx = new HashMap<Descriptor, Integer>();
436           int offset = md.isStatic() ? 0 : 1;
437           for (int i = 0; i < md.numParameters(); i++) {
438             Descriptor paramDesc = (Descriptor) md.getParameter(i);
439             mapParamDescToIdx.put(paramDesc, new Integer(i + offset));
440           }
441
442           FlowGraph fg = new FlowGraph(md, mapParamDescToIdx);
443           mapMethodDescriptorToFlowGraph.put(md, fg);
444
445           analyzeMethodBody(cd, md);
446         }
447       }
448     }
449
450     _debug_printGraph();
451   }
452
453   private void analyzeMethodBody(ClassDescriptor cd, MethodDescriptor md) {
454     BlockNode bn = state.getMethodBody(md);
455     NodeTupleSet implicitFlowTupleSet = new NodeTupleSet();
456     analyzeFlowBlockNode(md, md.getParameterTable(), bn, implicitFlowTupleSet);
457   }
458
459   private void analyzeFlowBlockNode(MethodDescriptor md, SymbolTable nametable, BlockNode bn,
460       NodeTupleSet implicitFlowTupleSet) {
461
462     bn.getVarTable().setParent(nametable);
463     for (int i = 0; i < bn.size(); i++) {
464       BlockStatementNode bsn = bn.get(i);
465       analyzeBlockStatementNode(md, bn.getVarTable(), bsn, implicitFlowTupleSet);
466     }
467
468   }
469
470   private void analyzeBlockStatementNode(MethodDescriptor md, SymbolTable nametable,
471       BlockStatementNode bsn, NodeTupleSet implicitFlowTupleSet) {
472
473     switch (bsn.kind()) {
474     case Kind.BlockExpressionNode:
475       analyzeBlockExpressionNode(md, nametable, (BlockExpressionNode) bsn, implicitFlowTupleSet);
476       break;
477
478     case Kind.DeclarationNode:
479       analyzeFlowDeclarationNode(md, nametable, (DeclarationNode) bsn, implicitFlowTupleSet);
480       break;
481
482     case Kind.IfStatementNode:
483       analyzeFlowIfStatementNode(md, nametable, (IfStatementNode) bsn, implicitFlowTupleSet);
484       break;
485
486     case Kind.LoopNode:
487       analyzeFlowLoopNode(md, nametable, (LoopNode) bsn, implicitFlowTupleSet);
488       break;
489
490     case Kind.ReturnNode:
491       analyzeReturnNode(md, nametable, (ReturnNode) bsn);
492       break;
493
494     case Kind.SubBlockNode:
495       analyzeFlowSubBlockNode(md, nametable, (SubBlockNode) bsn, implicitFlowTupleSet);
496       break;
497
498     case Kind.ContinueBreakNode:
499       break;
500
501     case Kind.SwitchStatementNode:
502       analyzeSwitchStatementNode(md, nametable, (SwitchStatementNode) bsn);
503       break;
504
505     }
506
507   }
508
509   private void analyzeSwitchStatementNode(MethodDescriptor md, SymbolTable nametable,
510       SwitchStatementNode bsn) {
511     // TODO Auto-generated method stub
512
513   }
514
515   private void analyzeFlowSubBlockNode(MethodDescriptor md, SymbolTable nametable,
516       SubBlockNode sbn, NodeTupleSet implicitFlowTupleSet) {
517     analyzeFlowBlockNode(md, nametable, sbn.getBlockNode(), implicitFlowTupleSet);
518   }
519
520   private void analyzeReturnNode(MethodDescriptor md, SymbolTable nametable, ReturnNode bsn) {
521     // TODO Auto-generated method stub
522
523   }
524
525   private void analyzeFlowLoopNode(MethodDescriptor md, SymbolTable nametable, LoopNode ln,
526       NodeTupleSet implicitFlowTupleSet) {
527
528     if (ln.getType() == LoopNode.WHILELOOP || ln.getType() == LoopNode.DOWHILELOOP) {
529
530       NodeTupleSet condTupleNode = new NodeTupleSet();
531       analyzeFlowExpressionNode(md, nametable, ln.getCondition(), condTupleNode, null,
532           implicitFlowTupleSet, false);
533       condTupleNode.addTupleSet(implicitFlowTupleSet);
534
535       // add edges from condNodeTupleSet to all nodes of conditional nodes
536       analyzeFlowBlockNode(md, nametable, ln.getBody(), condTupleNode);
537
538     } else {
539       // check 'for loop' case
540       BlockNode bn = ln.getInitializer();
541       analyzeFlowBlockNode(md, bn.getVarTable(), bn, implicitFlowTupleSet);
542       bn.getVarTable().setParent(nametable);
543
544       NodeTupleSet condTupleNode = new NodeTupleSet();
545       analyzeFlowExpressionNode(md, bn.getVarTable(), ln.getCondition(), condTupleNode, null,
546           implicitFlowTupleSet, false);
547       condTupleNode.addTupleSet(implicitFlowTupleSet);
548
549       analyzeFlowBlockNode(md, bn.getVarTable(), ln.getUpdate(), condTupleNode);
550       analyzeFlowBlockNode(md, bn.getVarTable(), ln.getBody(), condTupleNode);
551
552     }
553
554   }
555
556   private void analyzeFlowIfStatementNode(MethodDescriptor md, SymbolTable nametable,
557       IfStatementNode isn, NodeTupleSet implicitFlowTupleSet) {
558
559     NodeTupleSet condTupleNode = new NodeTupleSet();
560     analyzeFlowExpressionNode(md, nametable, isn.getCondition(), condTupleNode, null,
561         implicitFlowTupleSet, false);
562
563     // add edges from condNodeTupleSet to all nodes of conditional nodes
564     condTupleNode.addTupleSet(implicitFlowTupleSet);
565     analyzeFlowBlockNode(md, nametable, isn.getTrueBlock(), condTupleNode);
566
567     if (isn.getFalseBlock() != null) {
568       analyzeFlowBlockNode(md, nametable, isn.getFalseBlock(), condTupleNode);
569     }
570
571   }
572
573   private void analyzeFlowDeclarationNode(MethodDescriptor md, SymbolTable nametable,
574       DeclarationNode dn, NodeTupleSet implicitFlowTupleSet) {
575
576     VarDescriptor vd = dn.getVarDescriptor();
577     NTuple<Descriptor> tupleLHS = new NTuple<Descriptor>();
578     tupleLHS.add(vd);
579     getFlowGraph(md).createNewFlowNode(tupleLHS);
580
581     if (dn.getExpression() != null) {
582
583       NodeTupleSet tupleSetRHS = new NodeTupleSet();
584       analyzeFlowExpressionNode(md, nametable, dn.getExpression(), tupleSetRHS, null,
585           implicitFlowTupleSet, false);
586
587       // add a new flow edge from rhs to lhs
588       for (Iterator<NTuple<Descriptor>> iter = tupleSetRHS.iterator(); iter.hasNext();) {
589         NTuple<Descriptor> from = iter.next();
590         addFlowGraphEdge(md, from, tupleLHS);
591       }
592
593     }
594
595   }
596
597   private void analyzeBlockExpressionNode(MethodDescriptor md, SymbolTable nametable,
598       BlockExpressionNode ben, NodeTupleSet implicitFlowTupleSet) {
599     analyzeFlowExpressionNode(md, nametable, ben.getExpression(), null, null, implicitFlowTupleSet,
600         false);
601   }
602
603   private NTuple<Descriptor> analyzeFlowExpressionNode(MethodDescriptor md, SymbolTable nametable,
604       ExpressionNode en, NodeTupleSet nodeSet, boolean isLHS) {
605     return analyzeFlowExpressionNode(md, nametable, en, nodeSet, null, new NodeTupleSet(), isLHS);
606   }
607
608   private NTuple<Descriptor> analyzeFlowExpressionNode(MethodDescriptor md, SymbolTable nametable,
609       ExpressionNode en, NodeTupleSet nodeSet, NTuple<Descriptor> base,
610       NodeTupleSet implicitFlowTupleSet, boolean isLHS) {
611
612     // note that expression node can create more than one flow node
613     // nodeSet contains of flow nodes
614     // base is always assigned to null except name node case!
615
616     NTuple<Descriptor> flowTuple;
617
618     switch (en.kind()) {
619
620     case Kind.AssignmentNode:
621       analyzeFlowAssignmentNode(md, nametable, (AssignmentNode) en, base, implicitFlowTupleSet);
622       break;
623
624     case Kind.FieldAccessNode:
625       flowTuple =
626           analyzeFlowFieldAccessNode(md, nametable, (FieldAccessNode) en, nodeSet, base,
627               implicitFlowTupleSet);
628       nodeSet.addTuple(flowTuple);
629       return flowTuple;
630
631     case Kind.NameNode:
632       NodeTupleSet nameNodeSet = new NodeTupleSet();
633       flowTuple =
634           analyzeFlowNameNode(md, nametable, (NameNode) en, nameNodeSet, base, implicitFlowTupleSet);
635       nodeSet.addTuple(flowTuple);
636       return flowTuple;
637
638     case Kind.OpNode:
639       analyzeFlowOpNode(md, nametable, (OpNode) en, nodeSet, implicitFlowTupleSet);
640       break;
641
642     case Kind.CreateObjectNode:
643       analyzeCreateObjectNode(md, nametable, (CreateObjectNode) en);
644       break;
645
646     case Kind.ArrayAccessNode:
647       analyzeFlowArrayAccessNode(md, nametable, (ArrayAccessNode) en, nodeSet, isLHS);
648       break;
649
650     case Kind.LiteralNode:
651       analyzeLiteralNode(md, nametable, (LiteralNode) en);
652       break;
653
654     case Kind.MethodInvokeNode:
655       analyzeFlowMethodInvokeNode(md, nametable, (MethodInvokeNode) en, implicitFlowTupleSet);
656       break;
657
658     case Kind.TertiaryNode:
659       analyzeFlowTertiaryNode(md, nametable, (TertiaryNode) en, nodeSet, implicitFlowTupleSet);
660       break;
661
662     case Kind.CastNode:
663       analyzeFlowCastNode(md, nametable, (CastNode) en, implicitFlowTupleSet);
664       break;
665
666     // case Kind.InstanceOfNode:
667     // checkInstanceOfNode(md, nametable, (InstanceOfNode) en, td);
668     // return null;
669
670     // case Kind.ArrayInitializerNode:
671     // checkArrayInitializerNode(md, nametable, (ArrayInitializerNode) en,
672     // td);
673     // return null;
674
675     // case Kind.ClassTypeNode:
676     // checkClassTypeNode(md, nametable, (ClassTypeNode) en, td);
677     // return null;
678
679     // case Kind.OffsetNode:
680     // checkOffsetNode(md, nametable, (OffsetNode)en, td);
681     // return null;
682
683     }
684     return null;
685
686   }
687
688   private void analyzeFlowCastNode(MethodDescriptor md, SymbolTable nametable, CastNode cn,
689       NodeTupleSet implicitFlowTupleSet) {
690
691     NodeTupleSet nodeTupleSet = new NodeTupleSet();
692     analyzeFlowExpressionNode(md, nametable, cn.getExpression(), nodeTupleSet, false);
693
694   }
695
696   private void analyzeFlowTertiaryNode(MethodDescriptor md, SymbolTable nametable, TertiaryNode tn,
697       NodeTupleSet nodeSet, NodeTupleSet implicitFlowTupleSet) {
698
699     System.out.println("### analyzeFlowTertiaryNode=" + tn.printNode(0));
700
701     NodeTupleSet tertiaryTupleNode = new NodeTupleSet();
702     analyzeFlowExpressionNode(md, nametable, tn.getCond(), tertiaryTupleNode, null,
703         implicitFlowTupleSet, false);
704
705     // add edges from tertiaryTupleNode to all nodes of conditional nodes
706     tertiaryTupleNode.addTupleSet(implicitFlowTupleSet);
707     System.out.println("### TertiarayNode's condition=" + tertiaryTupleNode);
708     analyzeFlowExpressionNode(md, nametable, tn.getTrueExpr(), tertiaryTupleNode, null,
709         implicitFlowTupleSet, false);
710
711     analyzeFlowExpressionNode(md, nametable, tn.getFalseExpr(), tertiaryTupleNode, null,
712         implicitFlowTupleSet, false);
713
714     nodeSet.addTupleSet(tertiaryTupleNode);
715
716   }
717
718   private void addMapCallerMethodDescToMethodInvokeNodeSet(MethodDescriptor caller,
719       MethodInvokeNode min) {
720     Set<MethodInvokeNode> set = mapMethodDescriptorToMethodInvokeNodeSet.get(caller);
721     if (set == null) {
722       set = new HashSet<MethodInvokeNode>();
723       mapMethodDescriptorToMethodInvokeNodeSet.put(caller, set);
724     }
725     set.add(min);
726   }
727
728   private void analyzeFlowMethodInvokeNode(MethodDescriptor md, SymbolTable nametable,
729       MethodInvokeNode min, NodeTupleSet implicitFlowTupleSet) {
730
731     addMapCallerMethodDescToMethodInvokeNodeSet(md, min);
732
733     MethodDescriptor calleeMD = min.getMethod();
734
735     NameDescriptor baseName = min.getBaseName();
736     boolean isSystemout = false;
737     if (baseName != null) {
738       isSystemout = baseName.getSymbol().equals("System.out");
739     }
740
741     if (!ssjava.isSSJavaUtil(calleeMD.getClassDesc()) && !ssjava.isTrustMethod(calleeMD)
742         && !calleeMD.getModifiers().isNative() && !isSystemout) {
743
744       // CompositeLocation baseLocation = null;
745       if (min.getExpression() != null) {
746
747         NodeTupleSet baseNodeSet = new NodeTupleSet();
748         System.out.println("Analyzing base of method=" + min.getExpression());
749         analyzeFlowExpressionNode(calleeMD, nametable, min.getExpression(), baseNodeSet, null,
750             implicitFlowTupleSet, false);
751
752       } else {
753         if (min.getMethod().isStatic()) {
754           // String globalLocId = ssjava.getMethodLattice(md).getGlobalLoc();
755           // if (globalLocId == null) {
756           // throw new
757           // Error("Method lattice does not define global variable location at "
758           // + generateErrorMessage(md.getClassDesc(), min));
759           // }
760           // baseLocation = new CompositeLocation(new Location(md,
761           // globalLocId));
762         } else {
763           // 'this' var case
764           // String thisLocId = ssjava.getMethodLattice(md).getThisLoc();
765           // baseLocation = new CompositeLocation(new Location(md, thisLocId));
766         }
767       }
768
769       // constraint case:
770       // if (constraint != null) {
771       // int compareResult =
772       // CompositeLattice.compare(constraint, baseLocation, true,
773       // generateErrorMessage(cd, min));
774       // if (compareResult != ComparisonResult.GREATER) {
775       // // if the current constraint is higher than method's THIS location
776       // // no need to check constraints!
777       // CompositeLocation calleeConstraint =
778       // translateCallerLocToCalleeLoc(calleeMD, baseLocation, constraint);
779       // // System.out.println("check method body for constraint:" + calleeMD +
780       // // " calleeConstraint="
781       // // + calleeConstraint);
782       // checkMethodBody(calleeMD.getClassDesc(), calleeMD, calleeConstraint);
783       // }
784       // }
785
786       analyzeFlowMethodParameters(md, nametable, min);
787
788       // checkCalleeConstraints(md, nametable, min, baseLocation, constraint);
789
790       // checkCallerArgumentLocationConstraints(md, nametable, min,
791       // baseLocation, constraint);
792
793       if (!min.getMethod().getReturnType().isVoid()) {
794         // If method has a return value, compute the highest possible return
795         // location in the caller's perspective
796         // CompositeLocation ceilingLoc =
797         // computeCeilingLocationForCaller(md, nametable, min, baseLocation,
798         // constraint);
799         // return ceilingLoc;
800       }
801     }
802
803     // return new CompositeLocation(Location.createTopLocation(md));
804
805   }
806
807   private NTuple<Descriptor> getArgTupleByArgIdx(MethodInvokeNode min, int idx) {
808     return mapMethodInvokeNodeToArgIdxMap.get(min).get(new Integer(idx));
809   }
810
811   private void addArgIdxMap(MethodInvokeNode min, int idx, NTuple<Descriptor> argTuple) {
812     Map<Integer, NTuple<Descriptor>> mapIdxToArgTuple = mapMethodInvokeNodeToArgIdxMap.get(min);
813     if (mapIdxToArgTuple == null) {
814       mapIdxToArgTuple = new HashMap<Integer, NTuple<Descriptor>>();
815       mapMethodInvokeNodeToArgIdxMap.put(min, mapIdxToArgTuple);
816     }
817     mapIdxToArgTuple.put(new Integer(idx), argTuple);
818   }
819
820   private void analyzeFlowMethodParameters(MethodDescriptor callermd, SymbolTable nametable,
821       MethodInvokeNode min) {
822
823     if (min.numArgs() > 0) {
824
825       int offset = min.getMethod().isStatic() ? 0 : 1;
826
827       for (int i = 0; i < min.numArgs(); i++) {
828         ExpressionNode en = min.getArg(i);
829         NTuple<Descriptor> argTuple =
830             analyzeFlowExpressionNode(callermd, nametable, en, new NodeTupleSet(), false);
831
832         addArgIdxMap(min, i + offset, argTuple);
833       }
834
835     }
836
837   }
838
839   private void analyzeLiteralNode(MethodDescriptor md, SymbolTable nametable, LiteralNode en) {
840     // TODO Auto-generated method stub
841
842   }
843
844   private void analyzeFlowArrayAccessNode(MethodDescriptor md, SymbolTable nametable,
845       ArrayAccessNode aan, NodeTupleSet nodeSet, boolean isLHS) {
846
847     NodeTupleSet expNodeTupleSet = new NodeTupleSet();
848     analyzeFlowExpressionNode(md, nametable, aan.getExpression(), expNodeTupleSet, isLHS);
849
850     NodeTupleSet idxNodeTupleSet = new NodeTupleSet();
851     analyzeFlowExpressionNode(md, nametable, aan.getIndex(), idxNodeTupleSet, isLHS);
852
853     if (isLHS) {
854       // need to create an edge from idx to array
855
856       for (Iterator<NTuple<Descriptor>> idxIter = idxNodeTupleSet.iterator(); idxIter.hasNext();) {
857         NTuple<Descriptor> idxTuple = idxIter.next();
858         for (Iterator<NTuple<Descriptor>> arrIter = expNodeTupleSet.iterator(); arrIter.hasNext();) {
859           NTuple<Descriptor> arrTuple = arrIter.next();
860           getFlowGraph(md).addValueFlowEdge(idxTuple, arrTuple);
861         }
862       }
863
864       nodeSet.addTupleSet(expNodeTupleSet);
865     } else {
866       nodeSet.addTupleSet(expNodeTupleSet);
867       nodeSet.addTupleSet(idxNodeTupleSet);
868     }
869
870   }
871
872   private void analyzeCreateObjectNode(MethodDescriptor md, SymbolTable nametable,
873       CreateObjectNode en) {
874     // TODO Auto-generated method stub
875
876   }
877
878   private void analyzeFlowOpNode(MethodDescriptor md, SymbolTable nametable, OpNode on,
879       NodeTupleSet nodeSet, NodeTupleSet implicitFlowTupleSet) {
880
881     NodeTupleSet leftOpSet = new NodeTupleSet();
882     NodeTupleSet rightOpSet = new NodeTupleSet();
883
884     // left operand
885     System.out.println("Analyzing left op=" + on.getLeft().printNode(0) + "::"
886         + on.getLeft().getClass());
887     analyzeFlowExpressionNode(md, nametable, on.getLeft(), leftOpSet, null, implicitFlowTupleSet,
888         false);
889     System.out.println("leftOpSet=" + leftOpSet);
890
891     if (on.getRight() != null) {
892       // right operand
893       analyzeFlowExpressionNode(md, nametable, on.getRight(), rightOpSet, null,
894           implicitFlowTupleSet, false);
895       System.out.println("rightOpSet=" + rightOpSet);
896     }
897
898     Operation op = on.getOp();
899
900     switch (op.getOp()) {
901
902     case Operation.UNARYPLUS:
903     case Operation.UNARYMINUS:
904     case Operation.LOGIC_NOT:
905       // single operand
906       nodeSet.addTupleSet(leftOpSet);
907       break;
908
909     case Operation.LOGIC_OR:
910     case Operation.LOGIC_AND:
911     case Operation.COMP:
912     case Operation.BIT_OR:
913     case Operation.BIT_XOR:
914     case Operation.BIT_AND:
915     case Operation.ISAVAILABLE:
916     case Operation.EQUAL:
917     case Operation.NOTEQUAL:
918     case Operation.LT:
919     case Operation.GT:
920     case Operation.LTE:
921     case Operation.GTE:
922     case Operation.ADD:
923     case Operation.SUB:
924     case Operation.MULT:
925     case Operation.DIV:
926     case Operation.MOD:
927     case Operation.LEFTSHIFT:
928     case Operation.RIGHTSHIFT:
929     case Operation.URIGHTSHIFT:
930
931       // there are two operands
932       nodeSet.addTupleSet(leftOpSet);
933       nodeSet.addTupleSet(rightOpSet);
934       break;
935
936     default:
937       throw new Error(op.toString());
938     }
939   }
940
941   private NTuple<Descriptor> analyzeFlowNameNode(MethodDescriptor md, SymbolTable nametable,
942       NameNode nn, NodeTupleSet nodeSet, NTuple<Descriptor> base, NodeTupleSet implicitFlowTupleSet) {
943
944     if (base == null) {
945       base = new NTuple<Descriptor>();
946     }
947
948     NameDescriptor nd = nn.getName();
949
950     if (nd.getBase() != null) {
951       analyzeFlowExpressionNode(md, nametable, nn.getExpression(), nodeSet, base,
952           implicitFlowTupleSet, false);
953     } else {
954       String varname = nd.toString();
955       if (varname.equals("this")) {
956         // 'this' itself!
957         base.add(md.getThis());
958         return base;
959       }
960
961       Descriptor d = (Descriptor) nametable.get(varname);
962
963       if (d instanceof VarDescriptor) {
964         VarDescriptor vd = (VarDescriptor) d;
965         base.add(vd);
966       } else if (d instanceof FieldDescriptor) {
967         // the type of field descriptor has a location!
968         FieldDescriptor fd = (FieldDescriptor) d;
969         if (fd.isStatic()) {
970           if (fd.isFinal()) {
971             // if it is 'static final', the location has TOP since no one can
972             // change its value
973             // loc.addLocation(Location.createTopLocation(md));
974             // return loc;
975           } else {
976             // if 'static', the location has pre-assigned global loc
977             // MethodLattice<String> localLattice = ssjava.getMethodLattice(md);
978             // String globalLocId = localLattice.getGlobalLoc();
979             // if (globalLocId == null) {
980             // throw new
981             // Error("Global location element is not defined in the method " +
982             // md);
983             // }
984             // Location globalLoc = new Location(md, globalLocId);
985             //
986             // loc.addLocation(globalLoc);
987           }
988         } else {
989           // the location of field access starts from this, followed by field
990           // location
991           base.add(md.getThis());
992         }
993
994         base.add(fd);
995       } else if (d == null) {
996         // access static field
997         // FieldDescriptor fd = nn.getField();addFlowGraphEdge
998         //
999         // MethodLattice<String> localLattice = ssjava.getMethodLattice(md);
1000         // String globalLocId = localLattice.getGlobalLoc();
1001         // if (globalLocId == null) {
1002         // throw new
1003         // Error("Method lattice does not define global variable location at "
1004         // + generateErrorMessage(md.getClassDesc(), nn));
1005         // }
1006         // loc.addLocation(new Location(md, globalLocId));
1007         //
1008         // Location fieldLoc = (Location) fd.getType().getExtension();
1009         // loc.addLocation(fieldLoc);
1010         //
1011         // return loc;
1012
1013       }
1014     }
1015
1016     getFlowGraph(md).createNewFlowNode(base);
1017
1018     return base;
1019
1020   }
1021
1022   private NTuple<Descriptor> analyzeFlowFieldAccessNode(MethodDescriptor md, SymbolTable nametable,
1023       FieldAccessNode fan, NodeTupleSet nodeSet, NTuple<Descriptor> base,
1024       NodeTupleSet implicitFlowTupleSet) {
1025
1026     ExpressionNode left = fan.getExpression();
1027     TypeDescriptor ltd = left.getType();
1028     FieldDescriptor fd = fan.getField();
1029
1030     String varName = null;
1031     if (left.kind() == Kind.NameNode) {
1032       NameDescriptor nd = ((NameNode) left).getName();
1033       varName = nd.toString();
1034     }
1035
1036     if (ltd.isClassNameRef() || (varName != null && varName.equals("this"))) {
1037       // using a class name directly or access using this
1038       if (fd.isStatic() && fd.isFinal()) {
1039         // loc.addLocation(Location.createTopLocation(md));
1040         // return loc;
1041       }
1042     }
1043
1044     // if (left instanceof ArrayAccessNode) {
1045     // ArrayAccessNode aan = (ArrayAccessNode) left;
1046     // left = aan.getExpression();
1047     // }
1048     // fanNodeSet
1049     base =
1050         analyzeFlowExpressionNode(md, nametable, left, nodeSet, base, implicitFlowTupleSet, false);
1051
1052     if (!left.getType().isPrimitive()) {
1053
1054       if (fd.getSymbol().equals("length")) {
1055         // TODO
1056         // array.length access, return the location of the array
1057         // return loc;
1058       }
1059
1060       base.add(fd);
1061     }
1062
1063     return base;
1064
1065   }
1066
1067   private void analyzeFlowAssignmentNode(MethodDescriptor md, SymbolTable nametable,
1068       AssignmentNode an, NTuple<Descriptor> base, NodeTupleSet implicitFlowTupleSet) {
1069
1070     System.out.println("analyzeFlowAssignmentNode=" + an);
1071
1072     NodeTupleSet nodeSetRHS = new NodeTupleSet();
1073     NodeTupleSet nodeSetLHS = new NodeTupleSet();
1074
1075     boolean postinc = true;
1076     if (an.getOperation().getBaseOp() == null
1077         || (an.getOperation().getBaseOp().getOp() != Operation.POSTINC && an.getOperation()
1078             .getBaseOp().getOp() != Operation.POSTDEC)) {
1079       postinc = false;
1080     }
1081
1082     // if LHS is array access node, need to capture value flows between an array
1083     // and its index value
1084     analyzeFlowExpressionNode(md, nametable, an.getDest(), nodeSetLHS, null, implicitFlowTupleSet,
1085         true);
1086     System.out.println("ASSIGNMENT NODE nodeSetLHS=" + nodeSetLHS);
1087
1088     if (!postinc) {
1089       // analyze value flows of rhs expression
1090       analyzeFlowExpressionNode(md, nametable, an.getSrc(), nodeSetRHS, null, implicitFlowTupleSet,
1091           false);
1092       System.out.println("ASSIGNMENT NODE nodeSetRHS=" + nodeSetRHS);
1093
1094       // creates edges from RHS to LHS
1095       for (Iterator<NTuple<Descriptor>> iter = nodeSetRHS.iterator(); iter.hasNext();) {
1096         NTuple<Descriptor> fromTuple = iter.next();
1097         for (Iterator<NTuple<Descriptor>> iter2 = nodeSetLHS.iterator(); iter2.hasNext();) {
1098           NTuple<Descriptor> toTuple = iter2.next();
1099           addFlowGraphEdge(md, fromTuple, toTuple);
1100         }
1101       }
1102
1103       // creates edges from implicitFlowTupleSet to LHS
1104       for (Iterator<NTuple<Descriptor>> iter = implicitFlowTupleSet.iterator(); iter.hasNext();) {
1105         NTuple<Descriptor> fromTuple = iter.next();
1106         for (Iterator<NTuple<Descriptor>> iter2 = nodeSetLHS.iterator(); iter2.hasNext();) {
1107           NTuple<Descriptor> toTuple = iter2.next();
1108           addFlowGraphEdge(md, fromTuple, toTuple);
1109         }
1110       }
1111
1112     } else {
1113       // postinc case
1114       for (Iterator<NTuple<Descriptor>> iter2 = nodeSetLHS.iterator(); iter2.hasNext();) {
1115         NTuple<Descriptor> tuple = iter2.next();
1116         addFlowGraphEdge(md, tuple, tuple);
1117       }
1118
1119     }
1120
1121   }
1122
1123   public FlowGraph getFlowGraph(MethodDescriptor md) {
1124     return mapMethodDescriptorToFlowGraph.get(md);
1125   }
1126
1127   public void addFlowGraphEdge(MethodDescriptor md, NTuple<Descriptor> from, NTuple<Descriptor> to) {
1128     FlowGraph graph = getFlowGraph(md);
1129     graph.addValueFlowEdge(from, to);
1130   }
1131
1132   public void _debug_printGraph() {
1133     Set<MethodDescriptor> keySet = mapMethodDescriptorToFlowGraph.keySet();
1134
1135     for (Iterator<MethodDescriptor> iterator = keySet.iterator(); iterator.hasNext();) {
1136       MethodDescriptor md = (MethodDescriptor) iterator.next();
1137       FlowGraph fg = mapMethodDescriptorToFlowGraph.get(md);
1138       try {
1139         fg.writeGraph();
1140       } catch (IOException e) {
1141         e.printStackTrace();
1142       }
1143     }
1144
1145   }
1146
1147 }
1148
1149 class ParamIndexRelation {
1150   private Integer higherIdx;
1151   private Integer lowerIdx;
1152 }