fixes on method annoatation checking: when a method needs to be annotated, all of...
[IRC.git] / Robust / src / Analysis / SSJava / MethodAnnotationCheck.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.Set;
7
8 import IR.ClassDescriptor;
9 import IR.MethodDescriptor;
10 import IR.Operation;
11 import IR.State;
12 import IR.SymbolTable;
13 import IR.TypeUtil;
14 import IR.Tree.ArrayAccessNode;
15 import IR.Tree.ArrayInitializerNode;
16 import IR.Tree.AssignmentNode;
17 import IR.Tree.BlockExpressionNode;
18 import IR.Tree.BlockNode;
19 import IR.Tree.BlockStatementNode;
20 import IR.Tree.CastNode;
21 import IR.Tree.CreateObjectNode;
22 import IR.Tree.DeclarationNode;
23 import IR.Tree.ExpressionNode;
24 import IR.Tree.FieldAccessNode;
25 import IR.Tree.IfStatementNode;
26 import IR.Tree.InstanceOfNode;
27 import IR.Tree.Kind;
28 import IR.Tree.LoopNode;
29 import IR.Tree.MethodInvokeNode;
30 import IR.Tree.OpNode;
31 import IR.Tree.ReturnNode;
32 import IR.Tree.SubBlockNode;
33 import IR.Tree.TertiaryNode;
34 import Util.Pair;
35
36 public class MethodAnnotationCheck {
37
38   State state;
39   SSJavaAnalysis ssjava;
40   TypeUtil tu;
41
42   Set<MethodDescriptor> annotatedMDSet;
43   Hashtable<MethodDescriptor, Set<MethodDescriptor>> caller2calleeSet;
44
45   public MethodAnnotationCheck(SSJavaAnalysis ssjava, State state, TypeUtil tu) {
46     this.ssjava = ssjava;
47     this.state = state;
48     this.tu = tu;
49     caller2calleeSet = new Hashtable<MethodDescriptor, Set<MethodDescriptor>>();
50     annotatedMDSet = new HashSet<MethodDescriptor>();
51   }
52
53   public void methodAnnoatationCheck() {
54     SymbolTable classtable = state.getClassSymbolTable();
55     HashSet toanalyze = new HashSet();
56     toanalyze.addAll(classtable.getValueSet());
57     toanalyze.addAll(state.getTaskSymbolTable().getValueSet());
58     while (!toanalyze.isEmpty()) {
59       Object obj = toanalyze.iterator().next();
60       ClassDescriptor cd = (ClassDescriptor) obj;
61       toanalyze.remove(cd);
62
63       if (!cd.isInterface()) {
64         for (Iterator method_it = cd.getMethods(); method_it.hasNext();) {
65           MethodDescriptor md = (MethodDescriptor) method_it.next();
66           checkMethodBody(cd, md);
67         }
68       }
69
70     }
71
72     for (Iterator iterator = annotatedMDSet.iterator(); iterator.hasNext();) {
73       MethodDescriptor md = (MethodDescriptor) iterator.next();
74       ssjava.addAnnotationRequire(md);
75     }
76
77     Set<Pair> visited = new HashSet<Pair>();
78     Set<MethodDescriptor> tovisit = new HashSet<MethodDescriptor>();
79     tovisit.addAll(annotatedMDSet);
80
81     while (!tovisit.isEmpty()) {
82       MethodDescriptor callerMD = tovisit.iterator().next();
83       tovisit.remove(callerMD);
84
85       Set<MethodDescriptor> calleeSet = caller2calleeSet.get(callerMD);
86       if (calleeSet != null) {
87         for (Iterator iterator = calleeSet.iterator(); iterator.hasNext();) {
88           MethodDescriptor calleeMD = (MethodDescriptor) iterator.next();
89           Pair p = new Pair(callerMD, calleeMD);
90           if (!visited.contains(p)) {
91             visited.add(p);
92
93             if (calleeMD.getClassDesc().isInterface()) {
94               calleeMD.getClassDesc();
95             }
96
97             tovisit.add(calleeMD);
98
99             if (calleeMD.isAbstract()) {
100               Set<MethodDescriptor> possibleCalleeSet =
101                   (Set<MethodDescriptor>) ssjava.getCallGraph().getMethods(calleeMD);
102
103               for (Iterator iterator2 = possibleCalleeSet.iterator(); iterator2.hasNext();) {
104                 MethodDescriptor possibleCallee = (MethodDescriptor) iterator2.next();
105
106                 if (!possibleCallee.isAbstract()) {
107                   ssjava.addAnnotationRequire(possibleCallee);
108                   tovisit.add(possibleCallee);
109                 }
110
111               }
112
113             } else {
114               ssjava.addAnnotationRequire(calleeMD);
115             }
116
117           }
118         }
119       }
120     }
121
122   }
123
124   public void methodAnnoataionInheritanceCheck() {
125     // check If a method is annotated, any method that overrides it should
126     // be annotated.
127
128     Set<MethodDescriptor> tovisit = new HashSet<MethodDescriptor>();
129     tovisit.addAll(ssjava.getAnnotationRequireSet());
130
131     while (!tovisit.isEmpty()) {
132       MethodDescriptor md = tovisit.iterator().next();
133       tovisit.remove(md);
134
135       ClassDescriptor cd = md.getClassDesc();
136
137       Set subClassSet = tu.getSubClasses(cd);
138       if (subClassSet != null) {
139         for (Iterator iterator2 = subClassSet.iterator(); iterator2.hasNext();) {
140           ClassDescriptor subCD = (ClassDescriptor) iterator2.next();
141           Set possiblematches = subCD.getMethodTable().getSet(md.getSymbol());
142           for (Iterator methodit = possiblematches.iterator(); methodit.hasNext();) {
143             MethodDescriptor matchmd = (MethodDescriptor) methodit.next();
144             if (md.matches(matchmd)) {
145               if (matchmd.getClassDesc().equals(subCD)) {
146                 ssjava.addAnnotationRequire(matchmd);
147               }
148             }
149           }
150         }
151       }
152
153       // need to check super classess if the current method is inherited from
154       // them, all of ancestor method should be annoated
155       ClassDescriptor currentCd = cd;
156       ClassDescriptor superCd = tu.getSuper(currentCd);
157       while (!superCd.getSymbol().equals("Object")) {
158         Set possiblematches = superCd.getMethodTable().getSet(md.getSymbol());
159         for (Iterator methodit = possiblematches.iterator(); methodit.hasNext();) {
160           MethodDescriptor matchmd = (MethodDescriptor) methodit.next();
161           if (md.matches(matchmd)) {
162             ssjava.addAnnotationRequire(matchmd);
163           }
164         }
165         currentCd = superCd;
166         superCd = tu.getSuper(currentCd);
167       }
168
169       Set<ClassDescriptor> superIFSet = tu.getSuperIFs(cd);
170       for (Iterator iterator = superIFSet.iterator(); iterator.hasNext();) {
171         ClassDescriptor parentInterface = (ClassDescriptor) iterator.next();
172         Set possiblematches = parentInterface.getMethodTable().getSet(md.getSymbol());
173         for (Iterator methodit = possiblematches.iterator(); methodit.hasNext();) {
174           MethodDescriptor matchmd = (MethodDescriptor) methodit.next();
175           if (md.matches(matchmd)) {
176             ssjava.addAnnotationRequire(matchmd);
177           }
178         }
179       }
180
181     }
182
183   }
184
185   private void checkMethodBody(ClassDescriptor cd, MethodDescriptor md) {
186     BlockNode bn = state.getMethodBody(md);
187     checkBlockNode(md, md.getParameterTable(), bn, false);
188   }
189
190   private void checkBlockNode(MethodDescriptor md, SymbolTable nametable, BlockNode bn, boolean flag) {
191     bn.getVarTable().setParent(nametable);
192     String label = bn.getLabel();
193     boolean isSSJavaLoop = flag;
194     if (label != null && label.equals(ssjava.SSJAVA)) {
195       if (isSSJavaLoop) {
196         throw new Error("Only outermost loop can be the self-stabilizing loop.");
197       } else {
198         annotatedMDSet.add(md);
199         isSSJavaLoop = true;
200       }
201     }
202
203     for (int i = 0; i < bn.size(); i++) {
204       BlockStatementNode bsn = bn.get(i);
205       checkBlockStatementNode(md, bn.getVarTable(), bsn, isSSJavaLoop);
206     }
207
208   }
209
210   private void checkBlockStatementNode(MethodDescriptor md, SymbolTable nametable,
211       BlockStatementNode bsn, boolean flag) {
212
213     switch (bsn.kind()) {
214     case Kind.SubBlockNode:
215       checkSubBlockNode(md, nametable, (SubBlockNode) bsn, flag);
216       return;
217
218     case Kind.BlockExpressionNode:
219       checkBlockExpressionNode(md, nametable, (BlockExpressionNode) bsn, flag);
220       break;
221
222     case Kind.DeclarationNode:
223       checkDeclarationNode(md, nametable, (DeclarationNode) bsn, flag);
224       break;
225
226     case Kind.IfStatementNode:
227       checkIfStatementNode(md, nametable, (IfStatementNode) bsn, flag);
228       break;
229
230     case Kind.LoopNode:
231       checkLoopNode(md, nametable, (LoopNode) bsn, flag);
232       break;
233
234     case Kind.ReturnNode:
235       checkReturnNode(md, nametable, (ReturnNode) bsn, flag);
236       break;
237
238     }
239   }
240
241   private void checkDeclarationNode(MethodDescriptor md, SymbolTable nametable, DeclarationNode dn,
242       boolean flag) {
243     if (dn.getExpression() != null) {
244       checkExpressionNode(md, nametable, dn.getExpression(), flag);
245     }
246   }
247
248   private void checkReturnNode(MethodDescriptor md, SymbolTable nametable, ReturnNode rn,
249       boolean flag) {
250     if (rn.getReturnExpression() != null) {
251       if (md.getReturnType() != null) {
252         checkExpressionNode(md, nametable, rn.getReturnExpression(), flag);
253       }
254     }
255   }
256
257   private void checkLoopNode(MethodDescriptor md, SymbolTable nametable, LoopNode ln, boolean flag) {
258     if (ln.getType() == LoopNode.WHILELOOP || ln.getType() == LoopNode.DOWHILELOOP) {
259       checkExpressionNode(md, nametable, ln.getCondition(), flag);
260       checkBlockNode(md, nametable, ln.getBody(), flag);
261     } else {
262       // For loop case
263       /* Link in the initializer naming environment */
264       BlockNode bn = ln.getInitializer();
265       bn.getVarTable().setParent(nametable);
266       for (int i = 0; i < bn.size(); i++) {
267         BlockStatementNode bsn = bn.get(i);
268         checkBlockStatementNode(md, bn.getVarTable(), bsn, flag);
269       }
270       // check the condition
271       checkExpressionNode(md, bn.getVarTable(), ln.getCondition(), flag);
272       checkBlockNode(md, bn.getVarTable(), ln.getBody(), flag);
273       checkBlockNode(md, bn.getVarTable(), ln.getUpdate(), flag);
274     }
275   }
276
277   private void checkIfStatementNode(MethodDescriptor md, SymbolTable nametable,
278       IfStatementNode isn, boolean flag) {
279     checkExpressionNode(md, nametable, isn.getCondition(), flag);
280     checkBlockNode(md, nametable, isn.getTrueBlock(), flag);
281     if (isn.getFalseBlock() != null) {
282       checkBlockNode(md, nametable, isn.getFalseBlock(), flag);
283     }
284   }
285
286   private void checkSubBlockNode(MethodDescriptor md, SymbolTable nametable, SubBlockNode sbn,
287       boolean flag) {
288     checkBlockNode(md, nametable.getParent(), sbn.getBlockNode(), flag);
289   }
290
291   private void checkBlockExpressionNode(MethodDescriptor md, SymbolTable nametable,
292       BlockExpressionNode ben, boolean flag) {
293     checkExpressionNode(md, nametable, ben.getExpression(), flag);
294   }
295
296   private void checkExpressionNode(MethodDescriptor md, SymbolTable nametable, ExpressionNode en,
297       boolean flag) {
298     switch (en.kind()) {
299     case Kind.AssignmentNode:
300       checkAssignmentNode(md, nametable, (AssignmentNode) en, flag);
301       return;
302
303     case Kind.CastNode:
304       checkCastNode(md, nametable, (CastNode) en, flag);
305       return;
306
307     case Kind.CreateObjectNode:
308       checkCreateObjectNode(md, nametable, (CreateObjectNode) en, flag);
309       return;
310
311     case Kind.FieldAccessNode:
312       checkFieldAccessNode(md, nametable, (FieldAccessNode) en, flag);
313       return;
314
315     case Kind.ArrayAccessNode:
316       checkArrayAccessNode(md, nametable, (ArrayAccessNode) en, flag);
317       return;
318
319       // case Kind.LiteralNode:
320       // checkLiteralNode(md, nametable, (LiteralNode) en, flag);
321       // return;
322
323     case Kind.MethodInvokeNode:
324       checkMethodInvokeNode(md, nametable, (MethodInvokeNode) en, flag);
325       return;
326
327       // case Kind.NameNode:
328       // checkNameNode(md, nametable, (NameNode) en, flag);
329       // return;
330
331     case Kind.OpNode:
332       checkOpNode(md, nametable, (OpNode) en, flag);
333       return;
334
335       // case Kind.OffsetNode:
336       // checkOffsetNode(md, nametable, (OffsetNode) en, flag);
337       // return;
338
339     case Kind.TertiaryNode:
340       checkTertiaryNode(md, nametable, (TertiaryNode) en, flag);
341       return;
342
343     case Kind.InstanceOfNode:
344       checkInstanceOfNode(md, nametable, (InstanceOfNode) en, flag);
345       return;
346
347     case Kind.ArrayInitializerNode:
348       checkArrayInitializerNode(md, nametable, (ArrayInitializerNode) en, flag);
349       return;
350
351       // case Kind.ClassTypeNode:
352       // checkClassTypeNode(md, nametable, (ClassTypeNode) en, flag);
353       // return;
354     }
355   }
356
357   private void checkArrayInitializerNode(MethodDescriptor md, SymbolTable nametable,
358       ArrayInitializerNode ain, boolean flag) {
359
360     for (int i = 0; i < ain.numVarInitializers(); ++i) {
361       checkExpressionNode(md, nametable, ain.getVarInitializer(i), flag);
362     }
363
364   }
365
366   private void checkInstanceOfNode(MethodDescriptor md, SymbolTable nametable, InstanceOfNode tn,
367       boolean flag) {
368     checkExpressionNode(md, nametable, tn.getExpr(), flag);
369   }
370
371   private void checkTertiaryNode(MethodDescriptor md, SymbolTable nametable, TertiaryNode tn,
372       boolean flag) {
373     checkExpressionNode(md, nametable, tn.getCond(), flag);
374     checkExpressionNode(md, nametable, tn.getTrueExpr(), flag);
375     checkExpressionNode(md, nametable, tn.getFalseExpr(), flag);
376   }
377
378   private void checkOpNode(MethodDescriptor md, SymbolTable nametable, OpNode on, boolean flag) {
379
380     checkExpressionNode(md, nametable, on.getLeft(), flag);
381     if (on.getRight() != null) {
382       checkExpressionNode(md, nametable, on.getRight(), flag);
383     }
384
385   }
386
387   private void checkMethodInvokeNode(MethodDescriptor md, SymbolTable nametable,
388       MethodInvokeNode min, boolean flag) {
389     for (int i = 0; i < min.numArgs(); i++) {
390       ExpressionNode en = min.getArg(i);
391       checkExpressionNode(md, nametable, en, flag);
392     }
393
394     if (min.getExpression() != null) {
395       checkExpressionNode(md, nametable, min.getExpression(), flag);
396     }
397
398     if (flag) {
399       annotatedMDSet.add(min.getMethod());
400     }
401
402     Set<MethodDescriptor> mdSet = caller2calleeSet.get(md);
403     if (mdSet == null) {
404       mdSet = new HashSet<MethodDescriptor>();
405       caller2calleeSet.put(md, mdSet);
406     }
407     mdSet.add(min.getMethod());
408
409   }
410
411   private void checkArrayAccessNode(MethodDescriptor md, SymbolTable nametable,
412       ArrayAccessNode aan, boolean flag) {
413
414     ExpressionNode left = aan.getExpression();
415     checkExpressionNode(md, nametable, left, flag);
416     checkExpressionNode(md, nametable, aan.getIndex(), flag);
417
418   }
419
420   private void checkFieldAccessNode(MethodDescriptor md, SymbolTable nametable,
421       FieldAccessNode fan, boolean flag) {
422     ExpressionNode left = fan.getExpression();
423     checkExpressionNode(md, nametable, left, flag);
424   }
425
426   private void checkCreateObjectNode(MethodDescriptor md, SymbolTable nametable,
427       CreateObjectNode con, boolean flag) {
428
429     for (int i = 0; i < con.numArgs(); i++) {
430       ExpressionNode en = con.getArg(i);
431       checkExpressionNode(md, nametable, en, flag);
432     }
433
434   }
435
436   private void checkCastNode(MethodDescriptor md, SymbolTable nametable, CastNode cn, boolean flag) {
437     ExpressionNode en = cn.getExpression();
438     checkExpressionNode(md, nametable, en, flag);
439   }
440
441   private void checkAssignmentNode(MethodDescriptor md, SymbolTable nametable, AssignmentNode an,
442       boolean flag) {
443     boolean postinc = true;
444
445     if (an.getOperation().getBaseOp() == null
446         || (an.getOperation().getBaseOp().getOp() != Operation.POSTINC && an.getOperation()
447             .getBaseOp().getOp() != Operation.POSTDEC))
448       postinc = false;
449
450     if (!postinc) {
451       checkExpressionNode(md, nametable, an.getSrc(), flag);
452     }
453
454     checkExpressionNode(md, nametable, an.getDest(), flag);
455
456   }
457
458 }