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