1 package Analysis.SSJava;
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.Comparator;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import java.util.Iterator;
13 import IR.ClassDescriptor;
15 import IR.FieldDescriptor;
16 import IR.MethodDescriptor;
17 import IR.NameDescriptor;
20 import IR.SymbolTable;
21 import IR.TypeDescriptor;
22 import IR.VarDescriptor;
23 import IR.Tree.ArrayAccessNode;
24 import IR.Tree.AssignmentNode;
25 import IR.Tree.BlockExpressionNode;
26 import IR.Tree.BlockNode;
27 import IR.Tree.BlockStatementNode;
28 import IR.Tree.CastNode;
29 import IR.Tree.CreateObjectNode;
30 import IR.Tree.DeclarationNode;
31 import IR.Tree.ExpressionNode;
32 import IR.Tree.FieldAccessNode;
33 import IR.Tree.IfStatementNode;
35 import IR.Tree.LiteralNode;
36 import IR.Tree.LoopNode;
37 import IR.Tree.MethodInvokeNode;
38 import IR.Tree.NameNode;
39 import IR.Tree.OpNode;
40 import IR.Tree.ReturnNode;
41 import IR.Tree.SubBlockNode;
42 import IR.Tree.SwitchStatementNode;
43 import IR.Tree.TertiaryNode;
45 public class LocationInference {
48 SSJavaAnalysis ssjava;
50 List<ClassDescriptor> toanalyzeList;
51 List<MethodDescriptor> toanalyzeMethodList;
52 Map<MethodDescriptor, FlowGraph> mapMethodDescriptorToFlowGraph;
56 public LocationInference(SSJavaAnalysis ssjava, State state) {
59 this.toanalyzeList = new ArrayList<ClassDescriptor>();
60 this.toanalyzeMethodList = new ArrayList<MethodDescriptor>();
61 this.mapMethodDescriptorToFlowGraph = new HashMap<MethodDescriptor, FlowGraph>();
64 public void setupToAnalyze() {
65 SymbolTable classtable = state.getClassSymbolTable();
66 toanalyzeList.clear();
67 toanalyzeList.addAll(classtable.getValueSet());
68 Collections.sort(toanalyzeList, new Comparator<ClassDescriptor>() {
69 public int compare(ClassDescriptor o1, ClassDescriptor o2) {
70 return o1.getClassName().compareToIgnoreCase(o2.getClassName());
75 public void setupToAnalazeMethod(ClassDescriptor cd) {
77 SymbolTable methodtable = cd.getMethodTable();
78 toanalyzeMethodList.clear();
79 toanalyzeMethodList.addAll(methodtable.getValueSet());
80 Collections.sort(toanalyzeMethodList, new Comparator<MethodDescriptor>() {
81 public int compare(MethodDescriptor o1, MethodDescriptor o2) {
82 return o1.getSymbol().compareToIgnoreCase(o2.getSymbol());
87 public boolean toAnalyzeMethodIsEmpty() {
88 return toanalyzeMethodList.isEmpty();
91 public boolean toAnalyzeIsEmpty() {
92 return toanalyzeList.isEmpty();
95 public ClassDescriptor toAnalyzeNext() {
96 return toanalyzeList.remove(0);
99 public MethodDescriptor toAnalyzeMethodNext() {
100 return toanalyzeMethodList.remove(0);
103 public void inference() {
105 // 2) construct value flow graph
109 while (!toAnalyzeIsEmpty()) {
110 ClassDescriptor cd = toAnalyzeNext();
112 setupToAnalazeMethod(cd);
113 while (!toAnalyzeMethodIsEmpty()) {
114 MethodDescriptor md = toAnalyzeMethodNext();
115 if (ssjava.needTobeAnnotated(md)) {
116 if (state.SSJAVADEBUG) {
117 System.out.println("SSJAVA: Constructing a flow graph: " + md);
119 FlowGraph fg = new FlowGraph(md);
120 mapMethodDescriptorToFlowGraph.put(md, fg);
121 analyzeMethodBody(cd, md);
128 private void analyzeMethodBody(ClassDescriptor cd, MethodDescriptor md) {
129 BlockNode bn = state.getMethodBody(md);
130 analyzeBlockNode(md, md.getParameterTable(), bn);
133 private void analyzeBlockNode(MethodDescriptor md, SymbolTable nametable, BlockNode bn) {
135 bn.getVarTable().setParent(nametable);
136 for (int i = 0; i < bn.size(); i++) {
137 BlockStatementNode bsn = bn.get(i);
138 analyzeBlockStatementNode(md, bn.getVarTable(), bsn);
143 private void analyzeBlockStatementNode(MethodDescriptor md, SymbolTable nametable,
144 BlockStatementNode bsn) {
146 switch (bsn.kind()) {
147 case Kind.BlockExpressionNode:
148 analyzeBlockExpressionNode(md, nametable, (BlockExpressionNode) bsn);
151 case Kind.DeclarationNode:
152 analyzeFlowDeclarationNode(md, nametable, (DeclarationNode) bsn);
155 case Kind.IfStatementNode:
156 analyzeIfStatementNode(md, nametable, (IfStatementNode) bsn);
160 analyzeLoopNode(md, nametable, (LoopNode) bsn);
163 case Kind.ReturnNode:
164 analyzeReturnNode(md, nametable, (ReturnNode) bsn);
167 case Kind.SubBlockNode:
168 analyzeSubBlockNode(md, nametable, (SubBlockNode) bsn);
171 case Kind.ContinueBreakNode:
174 case Kind.SwitchStatementNode:
175 analyzeSwitchStatementNode(md, nametable, (SwitchStatementNode) bsn);
182 private void analyzeSwitchStatementNode(MethodDescriptor md, SymbolTable nametable,
183 SwitchStatementNode bsn) {
184 // TODO Auto-generated method stub
188 private void analyzeSubBlockNode(MethodDescriptor md, SymbolTable nametable, SubBlockNode bsn) {
189 // TODO Auto-generated method stub
193 private void analyzeReturnNode(MethodDescriptor md, SymbolTable nametable, ReturnNode bsn) {
194 // TODO Auto-generated method stub
198 private void analyzeLoopNode(MethodDescriptor md, SymbolTable nametable, LoopNode bsn) {
199 // TODO Auto-generated method stub
203 private void analyzeIfStatementNode(MethodDescriptor md, SymbolTable nametable,
204 IfStatementNode bsn) {
205 // TODO Auto-generated method stub
209 private void analyzeFlowDeclarationNode(MethodDescriptor md, SymbolTable nametable,
210 DeclarationNode dn) {
212 VarDescriptor vd = dn.getVarDescriptor();
213 NTuple<Descriptor> tupleLHS = new NTuple<Descriptor>();
215 getFlowGraph(md).createNewFlowNode(tupleLHS);
217 if (dn.getExpression() != null) {
219 NodeTupleSet tupleSetRHS = new NodeTupleSet();
220 analyzeFlowExpressionNode(md, nametable, dn.getExpression(), tupleSetRHS,
221 new NTuple<Descriptor>());
223 // add a new flow edge from rhs to lhs
224 for (Iterator<NTuple<Descriptor>> iter = tupleSetRHS.iterator(); iter.hasNext();) {
225 NTuple<Descriptor> from = iter.next();
226 addFlowGraphEdge(md, from, tupleLHS);
233 private void analyzeBlockExpressionNode(MethodDescriptor md, SymbolTable nametable,
234 BlockExpressionNode ben) {
235 analyzeFlowExpressionNode(md, nametable, ben.getExpression(), null, null);
238 private NTuple<Descriptor> analyzeFlowExpressionNode(MethodDescriptor md, SymbolTable nametable,
239 ExpressionNode en, NodeTupleSet nodeSet, NTuple<Descriptor> base) {
241 // note that expression node can create more than one flow node
242 // nodeSet contains of flow nodes
244 NTuple<Descriptor> flowTuple;
248 case Kind.AssignmentNode:
249 analyzeFlowAssignmentNode(md, nametable, (AssignmentNode) en, base);
252 case Kind.FieldAccessNode:
253 flowTuple = analyzeFlowFieldAccessNode(md, nametable, (FieldAccessNode) en, nodeSet, base);
254 nodeSet.addTuple(flowTuple);
258 NodeTupleSet nameNodeSet = new NodeTupleSet();
259 flowTuple = analyzeFlowNameNode(md, nametable, (NameNode) en, nameNodeSet, base);
260 nodeSet.addTuple(flowTuple);
264 // return analyzeOpNode(md, nametable, (OpNode) en, new
265 // HashSet<FlowNode>());
268 case Kind.CreateObjectNode:
269 analyzeCreateObjectNode(md, nametable, (CreateObjectNode) en);
272 case Kind.ArrayAccessNode:
273 analyzeArrayAccessNode(md, nametable, (ArrayAccessNode) en);
276 case Kind.LiteralNode:
277 analyzeLiteralNode(md, nametable, (LiteralNode) en);
280 case Kind.MethodInvokeNode:
281 analyzeMethodInvokeNode(md, nametable, (MethodInvokeNode) en);
284 case Kind.TertiaryNode:
285 analyzeTertiaryNode(md, nametable, (TertiaryNode) en);
289 analyzeCastNode(md, nametable, (CastNode) en);
292 // case Kind.InstanceOfNode:
293 // checkInstanceOfNode(md, nametable, (InstanceOfNode) en, td);
296 // case Kind.ArrayInitializerNode:
297 // checkArrayInitializerNode(md, nametable, (ArrayInitializerNode) en,
301 // case Kind.ClassTypeNode:
302 // checkClassTypeNode(md, nametable, (ClassTypeNode) en, td);
305 // case Kind.OffsetNode:
306 // checkOffsetNode(md, nametable, (OffsetNode)en, td);
314 private void analyzeCastNode(MethodDescriptor md, SymbolTable nametable, CastNode en) {
315 // TODO Auto-generated method stub
319 private void analyzeTertiaryNode(MethodDescriptor md, SymbolTable nametable, TertiaryNode en) {
320 // TODO Auto-generated method stub
324 private void analyzeMethodInvokeNode(MethodDescriptor md, SymbolTable nametable,
325 MethodInvokeNode en) {
326 // TODO Auto-generated method stub
330 private void analyzeLiteralNode(MethodDescriptor md, SymbolTable nametable, LiteralNode en) {
331 // TODO Auto-generated method stub
335 private void analyzeArrayAccessNode(MethodDescriptor md, SymbolTable nametable, ArrayAccessNode en) {
336 // TODO Auto-generated method stub
340 private void analyzeCreateObjectNode(MethodDescriptor md, SymbolTable nametable,
341 CreateObjectNode en) {
342 // TODO Auto-generated method stub
346 private Set<FlowNode> analyzeOpNode(MethodDescriptor md, SymbolTable nametable, OpNode on,
347 Set<FlowNode> nodeSet) {
349 ClassDescriptor cd = md.getClassDesc();
352 // NTuple<Descriptor> leftOpTuple =
353 // analyzeFlowExpressionNode(md, nametable, on.getLeft(), new
354 // NTuple<Descriptor>());
356 if (on.getRight() != null) {
358 // NTuple<Descriptor> rightOpTuple =
359 // analyzeFlowExpressionNode(md, nametable, on.getRight(), new
360 // NTuple<Descriptor>());
363 Operation op = on.getOp();
365 switch (op.getOp()) {
367 case Operation.UNARYPLUS:
368 case Operation.UNARYMINUS:
369 case Operation.LOGIC_NOT:
373 case Operation.LOGIC_OR:
374 case Operation.LOGIC_AND:
376 case Operation.BIT_OR:
377 case Operation.BIT_XOR:
378 case Operation.BIT_AND:
379 case Operation.ISAVAILABLE:
380 case Operation.EQUAL:
381 case Operation.NOTEQUAL:
391 case Operation.LEFTSHIFT:
392 case Operation.RIGHTSHIFT:
393 case Operation.URIGHTSHIFT:
395 Set<CompositeLocation> inputSet = new HashSet<CompositeLocation>();
396 // inputSet.add(leftLoc);
397 // inputSet.add(rightLoc);
398 // CompositeLocation glbCompLoc =
399 // CompositeLattice.calculateGLB(inputSet, generateErrorMessage(cd, on));
400 // return glbCompLoc;
403 throw new Error(op.toString());
407 private NTuple<Descriptor> analyzeFlowNameNode(MethodDescriptor md, SymbolTable nametable,
408 NameNode nn, NodeTupleSet nodeSet, NTuple<Descriptor> base) {
411 base = new NTuple<Descriptor>();
414 NameDescriptor nd = nn.getName();
415 if (nd.getBase() != null) {
416 analyzeFlowExpressionNode(md, nametable, nn.getExpression(), nodeSet, base);
418 String varname = nd.toString();
419 if (varname.equals("this")) {
421 base.add(md.getThis());
425 Descriptor d = (Descriptor) nametable.get(varname);
427 // CompositeLocation localLoc = null;
428 if (d instanceof VarDescriptor) {
429 VarDescriptor vd = (VarDescriptor) d;
430 // localLoc = d2loc.get(vd);
431 // the type of var descriptor has a composite location!
432 // loc = ((SSJavaType)
433 // vd.getType().getExtension()).getCompLoc().clone();
435 } else if (d instanceof FieldDescriptor) {
436 // the type of field descriptor has a location!
437 FieldDescriptor fd = (FieldDescriptor) d;
440 // if it is 'static final', the location has TOP since no one can
442 // loc.addLocation(Location.createTopLocation(md));
445 // if 'static', the location has pre-assigned global loc
446 // MethodLattice<String> localLattice = ssjava.getMethodLattice(md);
447 // String globalLocId = localLattice.getGlobalLoc();
448 // if (globalLocId == null) {
450 // Error("Global location element is not defined in the method " +
453 // Location globalLoc = new Location(md, globalLocId);
455 // loc.addLocation(globalLoc);
458 // the location of field access starts from this, followed by field
460 base.add(md.getThis());
464 } else if (d == null) {
465 // access static field
466 // FieldDescriptor fd = nn.getField();addFlowGraphEdge
468 // MethodLattice<String> localLattice = ssjava.getMethodLattice(md);
469 // String globalLocId = localLattice.getGlobalLoc();
470 // if (globalLocId == null) {
472 // Error("Method lattice does not define global variable location at "
473 // + generateErrorMessage(md.getClassDesc(), nn));
475 // loc.addLocation(new Location(md, globalLocId));
477 // Location fieldLoc = (Location) fd.getType().getExtension();
478 // loc.addLocation(fieldLoc);
485 getFlowGraph(md).createNewFlowNode(base);
491 private NTuple<Descriptor> analyzeFlowFieldAccessNode(MethodDescriptor md, SymbolTable nametable,
492 FieldAccessNode fan, NodeTupleSet nodeSet, NTuple<Descriptor> base) {
494 ExpressionNode left = fan.getExpression();
495 TypeDescriptor ltd = left.getType();
496 FieldDescriptor fd = fan.getField();
498 String varName = null;
499 if (left.kind() == Kind.NameNode) {
500 NameDescriptor nd = ((NameNode) left).getName();
501 varName = nd.toString();
504 if (ltd.isClassNameRef() || (varName != null && varName.equals("this"))) {
505 // using a class name directly or access using this
506 if (fd.isStatic() && fd.isFinal()) {
507 // loc.addLocation(Location.createTopLocation(md));
512 // if (left instanceof ArrayAccessNode) {
513 // ArrayAccessNode aan = (ArrayAccessNode) left;
514 // left = aan.getExpression();
517 base = analyzeFlowExpressionNode(md, nametable, left, nodeSet, base);
519 if (!left.getType().isPrimitive()) {
521 if (fd.getSymbol().equals("length")) {
523 // array.length access, return the location of the array
534 private void analyzeFlowAssignmentNode(MethodDescriptor md, SymbolTable nametable,
535 AssignmentNode an, NTuple<Descriptor> base) {
537 System.out.println("analyzeFlowAssignmentNode=" + an);
539 ClassDescriptor cd = md.getClassDesc();
541 NodeTupleSet nodeSetRHS = new NodeTupleSet();
542 NodeTupleSet nodeSetLHS = new NodeTupleSet();
544 boolean postinc = true;
545 if (an.getOperation().getBaseOp() == null
546 || (an.getOperation().getBaseOp().getOp() != Operation.POSTINC && an.getOperation()
547 .getBaseOp().getOp() != Operation.POSTDEC)) {
551 // if LHS is array access node, need to capture value flows between an array
552 // and its index value
553 analyzeFlowExpressionNode(md, nametable, an.getDest(), nodeSetLHS, base);
554 System.out.println("ASSIGNMENT NODE nodeSetLHS=" + nodeSetLHS);
555 // NTuple<Descriptor> lhsDescTuple = analyzeFlowExpressionNode(md,
556 // nametable, an.getDest(), base);
559 // analyze value flows of rhs expression
560 analyzeFlowExpressionNode(md, nametable, an.getSrc(), nodeSetRHS, null);
561 System.out.println("ASSIGNMENT NODE nodeSetRHS=" + nodeSetRHS);
566 // src & dest are same
570 // creates edges from RHS to LHS
571 for (Iterator<NTuple<Descriptor>> iter = nodeSetRHS.iterator(); iter.hasNext();) {
572 NTuple<Descriptor> fromTuple = iter.next();
573 for (Iterator<NTuple<Descriptor>> iter2 = nodeSetLHS.iterator(); iter2.hasNext();) {
574 NTuple<Descriptor> toTuple = iter2.next();
575 addFlowGraphEdge(md, fromTuple, toTuple);
581 public FlowGraph getFlowGraph(MethodDescriptor md) {
582 return mapMethodDescriptorToFlowGraph.get(md);
585 public void addFlowGraphEdge(MethodDescriptor md, NTuple<Descriptor> from, NTuple<Descriptor> to) {
586 FlowGraph graph = getFlowGraph(md);
587 graph.addValueFlowEdge(from, to);