keep the current snapshot before making further changes.
[IRC.git] / Robust / src / Analysis / SSJava / FlowDownCheck.java
1 package Analysis.SSJava;
2
3 import java.util.HashSet;
4 import java.util.Hashtable;
5 import java.util.Iterator;
6 import java.util.Map;
7 import java.util.Set;
8 import java.util.StringTokenizer;
9 import java.util.Vector;
10
11 import IR.AnnotationDescriptor;
12 import IR.ClassDescriptor;
13 import IR.Descriptor;
14 import IR.FieldDescriptor;
15 import IR.MethodDescriptor;
16 import IR.NameDescriptor;
17 import IR.Operation;
18 import IR.State;
19 import IR.SymbolTable;
20 import IR.TypeDescriptor;
21 import IR.VarDescriptor;
22 import IR.Tree.AssignmentNode;
23 import IR.Tree.BlockExpressionNode;
24 import IR.Tree.BlockNode;
25 import IR.Tree.BlockStatementNode;
26 import IR.Tree.DeclarationNode;
27 import IR.Tree.ExpressionNode;
28 import IR.Tree.FieldAccessNode;
29 import IR.Tree.Kind;
30 import IR.Tree.NameNode;
31 import IR.Tree.OpNode;
32 import Util.Lattice;
33
34 public class FlowDownCheck {
35
36   static State state;
37   HashSet toanalyze;
38   Hashtable<TypeDescriptor, Location> td2loc;
39   Hashtable<String, ClassDescriptor> id2cd;
40
41   public FlowDownCheck(State state) {
42     this.state = state;
43     this.toanalyze = new HashSet();
44     this.td2loc = new Hashtable<TypeDescriptor, Location>();
45     init();
46   }
47
48   public void init() {
49     id2cd = new Hashtable<String, ClassDescriptor>();
50     Hashtable cd2lattice = state.getCd2LocationOrder();
51
52     Set cdSet = cd2lattice.keySet();
53     for (Iterator iterator = cdSet.iterator(); iterator.hasNext();) {
54       ClassDescriptor cd = (ClassDescriptor) iterator.next();
55       Lattice<String> lattice = (Lattice<String>) cd2lattice.get(cd);
56
57       Set<String> locIdSet = lattice.getKeySet();
58       for (Iterator iterator2 = locIdSet.iterator(); iterator2.hasNext();) {
59         String locID = (String) iterator2.next();
60         id2cd.put(locID, cd);
61       }
62     }
63
64   }
65
66   public void flowDownCheck() {
67
68     SymbolTable classtable = state.getClassSymbolTable();
69     toanalyze.addAll(classtable.getValueSet());
70     toanalyze.addAll(state.getTaskSymbolTable().getValueSet());
71
72     // Do methods next
73     while (!toanalyze.isEmpty()) {
74       Object obj = toanalyze.iterator().next();
75       ClassDescriptor cd = (ClassDescriptor) obj;
76       toanalyze.remove(cd);
77       if (cd.isClassLibrary()) {
78         // doesn't care about class libraries now
79         continue;
80       }
81
82       checkClass(cd);
83
84       for (Iterator method_it = cd.getMethods(); method_it.hasNext();) {
85         MethodDescriptor md = (MethodDescriptor) method_it.next();
86         try {
87           checkMethodBody(cd, md);
88         } catch (Error e) {
89           System.out.println("Error in " + md);
90           throw e;
91         }
92       }
93     }
94   }
95
96   public void checkMethodBody(ClassDescriptor cd, MethodDescriptor md) {
97     ClassDescriptor superdesc = cd.getSuperDesc();
98     if (superdesc != null) {
99       Set possiblematches = superdesc.getMethodTable().getSet(md.getSymbol());
100       for (Iterator methodit = possiblematches.iterator(); methodit.hasNext();) {
101         MethodDescriptor matchmd = (MethodDescriptor) methodit.next();
102         if (md.matches(matchmd)) {
103           if (matchmd.getModifiers().isFinal()) {
104             throw new Error("Try to override final method in method:" + md + " declared in  " + cd);
105           }
106         }
107       }
108     }
109     BlockNode bn = state.getMethodBody(md);
110     checkBlockNode(md, md.getParameterTable(), bn);
111   }
112
113   public void checkBlockNode(MethodDescriptor md, SymbolTable nametable, BlockNode bn) {
114     /* Link in the naming environment */
115     bn.getVarTable().setParent(nametable);
116     for (int i = 0; i < bn.size(); i++) {
117       BlockStatementNode bsn = bn.get(i);
118       checkBlockStatementNode(md, bn.getVarTable(), bsn);
119     }
120   }
121
122   public void checkBlockStatementNode(MethodDescriptor md, SymbolTable nametable,
123       BlockStatementNode bsn) {
124
125     switch (bsn.kind()) {
126     case Kind.BlockExpressionNode:
127       checkBlockExpressionNode(md, nametable, (BlockExpressionNode) bsn);
128       return;
129
130     case Kind.DeclarationNode:
131       checkDeclarationNode(md, (DeclarationNode) bsn);
132       return;
133     }
134     /*
135      * switch (bsn.kind()) { case Kind.BlockExpressionNode:
136      * checkBlockExpressionNode(md, nametable, (BlockExpressionNode) bsn);
137      * return;
138      * 
139      * case Kind.DeclarationNode: checkDeclarationNode(md, nametable,
140      * (DeclarationNode) bsn); return;
141      * 
142      * case Kind.TagDeclarationNode: checkTagDeclarationNode(md, nametable,
143      * (TagDeclarationNode) bsn); return;
144      * 
145      * case Kind.IfStatementNode: checkIfStatementNode(md, nametable,
146      * (IfStatementNode) bsn); return;
147      * 
148      * case Kind.SwitchStatementNode: checkSwitchStatementNode(md, nametable,
149      * (SwitchStatementNode) bsn); return;
150      * 
151      * case Kind.LoopNode: checkLoopNode(md, nametable, (LoopNode) bsn); return;
152      * 
153      * case Kind.ReturnNode: checkReturnNode(md, nametable, (ReturnNode) bsn);
154      * return;
155      * 
156      * case Kind.TaskExitNode: checkTaskExitNode(md, nametable, (TaskExitNode)
157      * bsn); return;
158      * 
159      * case Kind.SubBlockNode: checkSubBlockNode(md, nametable, (SubBlockNode)
160      * bsn); return;
161      * 
162      * case Kind.AtomicNode: checkAtomicNode(md, nametable, (AtomicNode) bsn);
163      * return;
164      * 
165      * case Kind.SynchronizedNode: checkSynchronizedNode(md, nametable,
166      * (SynchronizedNode) bsn); return;
167      * 
168      * case Kind.ContinueBreakNode: checkContinueBreakNode(md, nametable,
169      * (ContinueBreakNode) bsn); return;
170      * 
171      * case Kind.SESENode: case Kind.GenReachNode: // do nothing, no semantic
172      * check for SESEs return; }
173      */
174     // throw new Error();
175   }
176
177   void checkBlockExpressionNode(MethodDescriptor md, SymbolTable nametable, BlockExpressionNode ben) {
178     checkExpressionNode(md, nametable, ben.getExpression(), null);
179   }
180
181   void checkExpressionNode(MethodDescriptor md, SymbolTable nametable, ExpressionNode en,
182       TypeDescriptor td) {
183
184     switch (en.kind()) {
185     case Kind.AssignmentNode:
186       checkAssignmentNode(md, nametable, (AssignmentNode) en, td);
187       return;
188
189     case Kind.OpNode:
190       checkOpNode(md, nametable, (OpNode) en, td);
191       return;
192
193     case Kind.FieldAccessNode:
194       checkFieldAccessNode(md, nametable, (FieldAccessNode) en, td);
195       return;
196
197     case Kind.NameNode:
198       checkNameNode(md, nametable, (NameNode) en, td);
199       return;
200
201     }
202
203     /*
204      * switch(en.kind()) { case Kind.AssignmentNode:
205      * checkAssignmentNode(md,nametable,(AssignmentNode)en,td); return;
206      * 
207      * case Kind.CastNode: checkCastNode(md,nametable,(CastNode)en,td); return;
208      * 
209      * case Kind.CreateObjectNode:
210      * checkCreateObjectNode(md,nametable,(CreateObjectNode)en,td); return;
211      * 
212      * case Kind.FieldAccessNode:
213      * checkFieldAccessNode(md,nametable,(FieldAccessNode)en,td); return;
214      * 
215      * case Kind.ArrayAccessNode:
216      * checkArrayAccessNode(md,nametable,(ArrayAccessNode)en,td); return;
217      * 
218      * case Kind.LiteralNode: checkLiteralNode(md,nametable,(LiteralNode)en,td);
219      * return;
220      * 
221      * case Kind.MethodInvokeNode:
222      * checkMethodInvokeNode(md,nametable,(MethodInvokeNode)en,td); return;
223      * 
224      * case Kind.NameNode: checkNameNode(md,nametable,(NameNode)en,td); return;
225      * 
226      * case Kind.OpNode: checkOpNode(md,nametable,(OpNode)en,td); return;
227      * 
228      * case Kind.OffsetNode: checkOffsetNode(md, nametable, (OffsetNode)en, td);
229      * return;
230      * 
231      * case Kind.TertiaryNode: checkTertiaryNode(md, nametable,
232      * (TertiaryNode)en, td); return;
233      * 
234      * case Kind.InstanceOfNode: checkInstanceOfNode(md, nametable,
235      * (InstanceOfNode) en, td); return;
236      * 
237      * case Kind.ArrayInitializerNode: checkArrayInitializerNode(md, nametable,
238      * (ArrayInitializerNode) en, td); return;
239      * 
240      * case Kind.ClassTypeNode: checkClassTypeNode(md, nametable,
241      * (ClassTypeNode) en, td); return; }
242      */
243   }
244
245   void checkNameNode(MethodDescriptor md, SymbolTable nametable, NameNode nn, TypeDescriptor td) {
246
247   }
248
249   void checkFieldAccessNode(MethodDescriptor md, SymbolTable nametable, FieldAccessNode fan,
250       TypeDescriptor td) {
251
252     ExpressionNode left = fan.getExpression();
253     checkExpressionNode(md, nametable, left, null);
254     TypeDescriptor ltd = left.getType();
255     String fieldname = fan.getFieldName();
256
257
258   }
259
260   void checkOpNode(MethodDescriptor md, SymbolTable nametable, OpNode on, TypeDescriptor td) {
261
262     Lattice<String> locOrder = (Lattice<String>) state.getCd2LocationOrder().get(md.getClassDesc());
263
264     checkExpressionNode(md, nametable, on.getLeft(), null);
265     if (on.getRight() != null)
266       checkExpressionNode(md, nametable, on.getRight(), null);
267
268     TypeDescriptor ltd = on.getLeft().getType();
269     TypeDescriptor rtd = on.getRight() != null ? on.getRight().getType() : null;
270
271     if (ltd.getAnnotationMarkers().size() == 0) {
272       // constant value
273       // TODO
274       // ltd.addAnnotationMarker(new AnnotationDescriptor(Lattice.TOP));
275     }
276     if (rtd != null && rtd.getAnnotationMarkers().size() == 0) {
277       // constant value
278       // TODO
279       // rtd.addAnnotationMarker(new AnnotationDescriptor(Lattice.TOP));
280     }
281
282     System.out.println("checking op node");
283     System.out.println("td=" + td);
284     System.out.println("ltd=" + ltd);
285     System.out.println("rtd=" + rtd);
286
287     Operation op = on.getOp();
288
289     switch (op.getOp()) {
290
291     case Operation.UNARYPLUS:
292     case Operation.UNARYMINUS:
293     case Operation.LOGIC_NOT:
294       // single operand
295       on.setType(new TypeDescriptor(TypeDescriptor.BOOLEAN));
296       break;
297
298     case Operation.LOGIC_OR:
299     case Operation.LOGIC_AND:
300     case Operation.COMP:
301     case Operation.BIT_OR:
302     case Operation.BIT_XOR:
303     case Operation.BIT_AND:
304     case Operation.ISAVAILABLE:
305     case Operation.EQUAL:
306     case Operation.NOTEQUAL:
307     case Operation.LT:
308     case Operation.GT:
309     case Operation.LTE:
310     case Operation.GTE:
311     case Operation.ADD:
312     case Operation.SUB:
313     case Operation.MULT:
314     case Operation.DIV:
315     case Operation.MOD:
316     case Operation.LEFTSHIFT:
317     case Operation.RIGHTSHIFT:
318     case Operation.URIGHTSHIFT:
319
320       Set<String> operandSet = new HashSet<String>();
321       String leftLoc = ltd.getAnnotationMarkers().get(0).getMarker();
322       String rightLoc = rtd.getAnnotationMarkers().get(0).getMarker();
323
324       operandSet.add(leftLoc);
325       operandSet.add(rightLoc);
326
327       // TODO
328       // String glbLoc = locOrder.getGLB(operandSet);
329       // on.getType().addAnnotationMarker(new AnnotationDescriptor(glbLoc));
330       // System.out.println(glbLoc + "<-" + leftLoc + " " + rightLoc);
331
332       break;
333
334     default:
335       throw new Error(op.toString());
336     }
337
338     if (td != null) {
339       String lhsLoc = td.getAnnotationMarkers().get(0).getMarker();
340       if (locOrder.isGreaterThan(lhsLoc, on.getType().getAnnotationMarkers().get(0).getMarker())) {
341         throw new Error("The location of LHS is higher than RHS: " + on.printNode(0));
342       }
343     }
344
345   }
346
347   void checkAssignmentNode(MethodDescriptor md, SymbolTable nametable, AssignmentNode an,
348       TypeDescriptor td) {
349
350     boolean postinc = true;
351     if (an.getOperation().getBaseOp() == null
352         || (an.getOperation().getBaseOp().getOp() != Operation.POSTINC && an.getOperation()
353             .getBaseOp().getOp() != Operation.POSTDEC))
354       postinc = false;
355     if (!postinc)
356       checkExpressionNode(md, nametable, an.getSrc(), td);
357
358
359     ClassDescriptor cd = md.getClassDesc();
360     Lattice<String> locOrder = (Lattice<String>) state.getCd2LocationOrder().get(cd);
361
362
363     Location destLocation = td2loc.get(an.getDest().getType());
364     Location srcLocation = td2loc.get(an.getSrc().getType());
365
366
367     if (!CompositeLattice.isGreaterThan(srcLocation, destLocation)) {
368       throw new Error("The value flow from " + srcLocation + " to " + destLocation
369           + " does not respect location hierarchy on the assignment " + an.printNode(0));
370     }
371
372
373   }
374
375   void checkDeclarationNode(MethodDescriptor md, DeclarationNode dn) {
376
377     ClassDescriptor cd = md.getClassDesc();
378     VarDescriptor vd = dn.getVarDescriptor();
379     Vector<AnnotationDescriptor> annotationVec = vd.getType().getAnnotationMarkers();
380
381     // currently enforce every variable to have corresponding location
382     if (annotationVec.size() == 0) {
383       throw new Error("Location is not assigned to variable " + vd.getSymbol() + " in the method "
384           + md.getSymbol() + " of the class " + cd.getSymbol());
385     }
386
387     if (annotationVec.size() > 1) {
388       // variable can have at most one location
389       throw new Error(vd.getSymbol() + " has more than one location.");
390     }
391
392     AnnotationDescriptor ad = annotationVec.elementAt(0);
393
394     if (ad.getType() == AnnotationDescriptor.MARKER_ANNOTATION) {
395
396       // check if location is defined
397       String locationID = ad.getMarker();
398       Lattice<String> lattice = (Lattice<String>) state.getCd2LocationOrder().get(cd);
399
400       if (lattice == null || (!lattice.containsKey(locationID))) {
401         throw new Error("Location " + locationID
402             + " is not defined in the location hierarchy of class " + cd.getSymbol() + ".");
403       }
404
405       Location loc = new Location(cd, locationID);
406       td2loc.put(vd.getType(), loc);
407
408     } else if (ad.getType() == AnnotationDescriptor.SINGLE_ANNOTATION) {
409       if (ad.getMarker().equals(SSJavaAnalysis.DELTA)) {
410
411         if (ad.getData().length() == 0) {
412           throw new Error("Delta function of " + vd.getSymbol() + " does not have any locations: "
413               + cd.getSymbol() + ".");
414         }
415
416         StringTokenizer token = new StringTokenizer(ad.getData(), ",");
417
418         CompositeLocation compLoc = new CompositeLocation(cd);
419         DeltaLocation deltaLoc = new DeltaLocation(cd);
420
421         while (token.hasMoreTokens()) {
422           String deltaOperand = token.nextToken();
423           ClassDescriptor deltaCD = id2cd.get(deltaOperand);
424           if (deltaCD == null) {
425             // delta operand is not defined in the location hierarchy
426             throw new Error("Delta operand '" + deltaOperand + "' of declaration node '" + vd
427                 + "' is not defined by location hierarchies.");
428           }
429
430           Location loc = new Location(deltaCD, deltaOperand);
431           deltaLoc.addDeltaOperand(loc);
432         }
433         compLoc.addLocation(deltaLoc);
434         td2loc.put(vd.getType(), compLoc);
435       }
436     }
437
438   }
439
440   private void checkClass(ClassDescriptor cd) {
441     // Check to see that fields are okay
442     for (Iterator field_it = cd.getFields(); field_it.hasNext();) {
443       FieldDescriptor fd = (FieldDescriptor) field_it.next();
444       checkFieldDeclaration(cd, fd);
445     }
446
447     // Check to see that methods respects ss property
448     for (Iterator method_it = cd.getMethods(); method_it.hasNext();) {
449       MethodDescriptor md = (MethodDescriptor) method_it.next();
450       checkMethodDeclaration(cd, md);
451     }
452   }
453
454   private void checkMethodDeclaration(ClassDescriptor cd, MethodDescriptor md) {
455
456   }
457
458   private void checkFieldDeclaration(ClassDescriptor cd, FieldDescriptor fd) {
459
460     Vector<AnnotationDescriptor> annotationVec = fd.getType().getAnnotationMarkers();
461
462     // currently enforce every variable to have corresponding location
463     if (annotationVec.size() == 0) {
464       throw new Error("Location is not assigned to the field " + fd.getSymbol() + " of the class "
465           + cd.getSymbol());
466     }
467
468     if (annotationVec.size() > 1) {
469       // variable can have at most one location
470       throw new Error("Field " + fd.getSymbol() + " of class " + cd
471           + " has more than one location.");
472     }
473
474     // check if location is defined
475     AnnotationDescriptor ad = annotationVec.elementAt(0);
476     if (ad.getType() == AnnotationDescriptor.MARKER_ANNOTATION) {
477       String locationID = annotationVec.elementAt(0).getMarker();
478       Lattice<String> lattice = (Lattice<String>) state.getCd2LocationOrder().get(cd);
479
480       if (lattice == null || (!lattice.containsKey(locationID))) {
481         throw new Error("Location " + locationID
482             + " is not defined in the location hierarchy of class " + cd.getSymbol() + ".");
483       }
484     } else if (ad.getType() == AnnotationDescriptor.SINGLE_ANNOTATION) {
485       if (ad.getMarker().equals(SSJavaAnalysis.DELTA)) {
486
487         if (ad.getData().length() == 0) {
488           throw new Error("Delta function of " + fd.getSymbol() + " does not have any locations: "
489               + cd.getSymbol() + ".");
490         }
491
492         CompositeLocation compLoc = new CompositeLocation(cd);
493         DeltaLocation deltaLoc = new DeltaLocation(cd);
494
495         StringTokenizer token = new StringTokenizer(ad.getData(), ",");
496         while (token.hasMoreTokens()) {
497           String deltaOperand = token.nextToken();
498           ClassDescriptor deltaCD = id2cd.get(deltaOperand);
499           if (deltaCD == null) {
500             // delta operand is not defined in the location hierarchy
501             throw new Error("Delta operand '" + deltaOperand + "' of field node '" + fd
502                 + "' is not defined by location hierarchies.");
503           }
504
505           Location loc = new Location(deltaCD, deltaOperand);
506           deltaLoc.addDeltaOperand(loc);
507         }
508         compLoc.addLocation(deltaLoc);
509         td2loc.put(fd.getType(), compLoc);
510
511       }
512     }
513
514   }
515
516   static class CompositeLattice {
517
518     public static boolean isGreaterThan(Location loc1, Location loc2) {
519
520       CompositeLocation compLoc1;
521       CompositeLocation compLoc2;
522
523       if (loc1 instanceof CompositeLocation) {
524         compLoc1 = (CompositeLocation) loc1;
525       } else {
526         // create a bogus composite location for a single location
527         compLoc1 = new CompositeLocation(loc1.getClassDescriptor());
528         compLoc1.addLocation(loc1);
529       }
530
531       if (loc2 instanceof CompositeLocation) {
532         compLoc2 = (CompositeLocation) loc2;
533       } else {
534         // create a bogus composite location for a single location
535         compLoc2 = new CompositeLocation(loc2.getClassDescriptor());
536         compLoc2.addLocation(loc2);
537       }
538
539       // comparing two composite locations
540
541       System.out.println("compare base location=" + compLoc1 + " ? " + compLoc2);
542
543       int baseCompareResult = compareBaseLocationSet(compLoc1, compLoc2);
544       if (baseCompareResult == ComparisonResult.EQUAL) {
545         // TODO
546         // need to compare # of delta operand
547       } else if (baseCompareResult == ComparisonResult.GREATER) {
548         return true;
549       } else {
550         return false;
551       }
552
553       return false;
554     }
555
556     private static int compareBaseLocationSet(CompositeLocation compLoc1, CompositeLocation compLoc2) {
557
558       // if compLoc1 is greater than compLoc2, return true
559       // else return false;
560
561       Map<ClassDescriptor, Location> cd2loc1 = compLoc1.getCd2Loc();
562       Map<ClassDescriptor, Location> cd2loc2 = compLoc2.getCd2Loc();
563
564       // compare base locations by class descriptor
565
566       Set<ClassDescriptor> keySet1 = cd2loc1.keySet();
567
568       int numEqualLoc = 0;
569
570       for (Iterator iterator = keySet1.iterator(); iterator.hasNext();) {
571         ClassDescriptor cd1 = (ClassDescriptor) iterator.next();
572
573         Location loc1 = cd2loc1.get(cd1);
574         Location loc2 = cd2loc2.get(cd1);
575
576         if (loc2 == null) {
577           // if comploc2 doesn't have corresponding location, then ignore this
578           // element
579           numEqualLoc++;
580           continue;
581         }
582
583         Lattice<String> locationOrder = (Lattice<String>) state.getCd2LocationOrder().get(cd1);
584         if (loc1.getLocIdentifier().equals(loc2.getLocIdentifier())) {
585           // have the same level of local hierarchy
586           numEqualLoc++;
587         } else if (!locationOrder.isGreaterThan(loc1.getLocIdentifier(), loc2.getLocIdentifier())) {
588           // if one element of composite location 1 is not higher than composite
589           // location 2
590           // then, composite loc 1 is not higher than composite loc 2
591
592           System.out.println(compLoc1 + " < " + compLoc2);
593           return ComparisonResult.LESS;
594         }
595
596       }
597
598       if (numEqualLoc == compLoc1.getTupleSize()) {
599         System.out.println(compLoc1 + " == " + compLoc2);
600         return ComparisonResult.EQUAL;
601       }
602
603       System.out.println(compLoc1 + " > " + compLoc2);
604       return ComparisonResult.GREATER;
605     }
606
607   }
608
609   class ComparisonResult {
610
611     public static final int GREATER = 0;
612     public static final int EQUAL = 1;
613     public static final int LESS = 2;
614     int result;
615
616   }
617
618 }