changes: 1) have a better error message 2) if annotation is required for abstract...
[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
98             tovisit.add(calleeMD);
99
100             if (calleeMD.isAbstract()) {
101               Set<MethodDescriptor> possibleCalleeSet =
102                   (Set<MethodDescriptor>) ssjava.getCallGraph().getMethods(calleeMD);
103
104               for (Iterator iterator2 = possibleCalleeSet.iterator(); iterator2.hasNext();) {
105                 MethodDescriptor possibleCallee = (MethodDescriptor) iterator2.next();
106
107                 if (!possibleCallee.isAbstract()) {
108                   ssjava.addAnnotationRequire(possibleCallee);
109                   tovisit.add(possibleCallee);
110                 }
111
112               }
113
114             } else {
115               ssjava.addAnnotationRequire(calleeMD);
116             }
117
118           }
119         }
120       }
121     }
122
123   }
124
125   public void methodAnnoataionInheritanceCheck() {
126     // check If a method is annotated, any method that overrides it should
127     // be annotated.
128
129     Set<MethodDescriptor> tovisit = new HashSet<MethodDescriptor>();
130     tovisit.addAll(ssjava.getAnnotationRequireSet());
131
132     while (!tovisit.isEmpty()) {
133       MethodDescriptor md = tovisit.iterator().next();
134       tovisit.remove(md);
135
136       ClassDescriptor cd = md.getClassDesc();
137
138       Set subClassSet = tu.getSubClasses(cd);
139       if (subClassSet != null) {
140         for (Iterator iterator2 = subClassSet.iterator(); iterator2.hasNext();) {
141           ClassDescriptor subCD = (ClassDescriptor) iterator2.next();
142           Set possiblematches = subCD.getMethodTable().getSet(md.getSymbol());
143           for (Iterator methodit = possiblematches.iterator(); methodit.hasNext();) {
144             MethodDescriptor matchmd = (MethodDescriptor) methodit.next();
145             if (md.matches(matchmd)) {
146               if (matchmd.getClassDesc().equals(subCD)) {
147                 ssjava.addAnnotationRequire(matchmd);
148               }
149             }
150           }
151         }
152       }
153     }
154
155   }
156
157   private void checkMethodBody(ClassDescriptor cd, MethodDescriptor md) {
158     BlockNode bn = state.getMethodBody(md);
159     checkBlockNode(md, md.getParameterTable(), bn, false);
160   }
161
162   private void checkBlockNode(MethodDescriptor md, SymbolTable nametable, BlockNode bn, boolean flag) {
163     bn.getVarTable().setParent(nametable);
164     String label = bn.getLabel();
165     boolean isSSJavaLoop = flag;
166     if (label != null && label.equals(ssjava.SSJAVA)) {
167       if (isSSJavaLoop) {
168         throw new Error("Only outermost loop can be the self-stabilizing loop.");
169       } else {
170         annotatedMDSet.add(md);
171         isSSJavaLoop = true;
172       }
173     }
174
175     for (int i = 0; i < bn.size(); i++) {
176       BlockStatementNode bsn = bn.get(i);
177       checkBlockStatementNode(md, bn.getVarTable(), bsn, isSSJavaLoop);
178     }
179
180   }
181
182   private void checkBlockStatementNode(MethodDescriptor md, SymbolTable nametable,
183       BlockStatementNode bsn, boolean flag) {
184
185     switch (bsn.kind()) {
186     case Kind.SubBlockNode:
187       checkSubBlockNode(md, nametable, (SubBlockNode) bsn, flag);
188       return;
189
190     case Kind.BlockExpressionNode:
191       checkBlockExpressionNode(md, nametable, (BlockExpressionNode) bsn, flag);
192       break;
193
194     case Kind.DeclarationNode:
195       checkDeclarationNode(md, nametable, (DeclarationNode) bsn, flag);
196       break;
197
198     case Kind.IfStatementNode:
199       checkIfStatementNode(md, nametable, (IfStatementNode) bsn, flag);
200       break;
201
202     case Kind.LoopNode:
203       checkLoopNode(md, nametable, (LoopNode) bsn, flag);
204       break;
205
206     case Kind.ReturnNode:
207       checkReturnNode(md, nametable, (ReturnNode) bsn, flag);
208       break;
209
210     }
211   }
212
213   private void checkDeclarationNode(MethodDescriptor md, SymbolTable nametable, DeclarationNode dn,
214       boolean flag) {
215     if (dn.getExpression() != null) {
216       checkExpressionNode(md, nametable, dn.getExpression(), flag);
217     }
218   }
219
220   private void checkReturnNode(MethodDescriptor md, SymbolTable nametable, ReturnNode rn,
221       boolean flag) {
222     if (rn.getReturnExpression() != null) {
223       if (md.getReturnType() != null) {
224         checkExpressionNode(md, nametable, rn.getReturnExpression(), flag);
225       }
226     }
227   }
228
229   private void checkLoopNode(MethodDescriptor md, SymbolTable nametable, LoopNode ln, boolean flag) {
230     if (ln.getType() == LoopNode.WHILELOOP || ln.getType() == LoopNode.DOWHILELOOP) {
231       checkExpressionNode(md, nametable, ln.getCondition(), flag);
232       checkBlockNode(md, nametable, ln.getBody(), flag);
233     } else {
234       // For loop case
235       /* Link in the initializer naming environment */
236       BlockNode bn = ln.getInitializer();
237       bn.getVarTable().setParent(nametable);
238       for (int i = 0; i < bn.size(); i++) {
239         BlockStatementNode bsn = bn.get(i);
240         checkBlockStatementNode(md, bn.getVarTable(), bsn, flag);
241       }
242       // check the condition
243       checkExpressionNode(md, bn.getVarTable(), ln.getCondition(), flag);
244       checkBlockNode(md, bn.getVarTable(), ln.getBody(), flag);
245       checkBlockNode(md, bn.getVarTable(), ln.getUpdate(), flag);
246     }
247   }
248
249   private void checkIfStatementNode(MethodDescriptor md, SymbolTable nametable,
250       IfStatementNode isn, boolean flag) {
251     checkExpressionNode(md, nametable, isn.getCondition(), flag);
252     checkBlockNode(md, nametable, isn.getTrueBlock(), flag);
253     if (isn.getFalseBlock() != null) {
254       checkBlockNode(md, nametable, isn.getFalseBlock(), flag);
255     }
256   }
257
258   private void checkSubBlockNode(MethodDescriptor md, SymbolTable nametable, SubBlockNode sbn,
259       boolean flag) {
260     checkBlockNode(md, nametable.getParent(), sbn.getBlockNode(), flag);
261   }
262
263   private void checkBlockExpressionNode(MethodDescriptor md, SymbolTable nametable,
264       BlockExpressionNode ben, boolean flag) {
265     checkExpressionNode(md, nametable, ben.getExpression(), flag);
266   }
267
268   private void checkExpressionNode(MethodDescriptor md, SymbolTable nametable, ExpressionNode en,
269       boolean flag) {
270     switch (en.kind()) {
271     case Kind.AssignmentNode:
272       checkAssignmentNode(md, nametable, (AssignmentNode) en, flag);
273       return;
274
275     case Kind.CastNode:
276       checkCastNode(md, nametable, (CastNode) en, flag);
277       return;
278
279     case Kind.CreateObjectNode:
280       checkCreateObjectNode(md, nametable, (CreateObjectNode) en, flag);
281       return;
282
283     case Kind.FieldAccessNode:
284       checkFieldAccessNode(md, nametable, (FieldAccessNode) en, flag);
285       return;
286
287     case Kind.ArrayAccessNode:
288       checkArrayAccessNode(md, nametable, (ArrayAccessNode) en, flag);
289       return;
290
291       // case Kind.LiteralNode:
292       // checkLiteralNode(md, nametable, (LiteralNode) en, flag);
293       // return;
294
295     case Kind.MethodInvokeNode:
296       checkMethodInvokeNode(md, nametable, (MethodInvokeNode) en, flag);
297       return;
298
299       // case Kind.NameNode:
300       // checkNameNode(md, nametable, (NameNode) en, flag);
301       // return;
302
303     case Kind.OpNode:
304       checkOpNode(md, nametable, (OpNode) en, flag);
305       return;
306
307       // case Kind.OffsetNode:
308       // checkOffsetNode(md, nametable, (OffsetNode) en, flag);
309       // return;
310
311     case Kind.TertiaryNode:
312       checkTertiaryNode(md, nametable, (TertiaryNode) en, flag);
313       return;
314
315     case Kind.InstanceOfNode:
316       checkInstanceOfNode(md, nametable, (InstanceOfNode) en, flag);
317       return;
318
319     case Kind.ArrayInitializerNode:
320       checkArrayInitializerNode(md, nametable, (ArrayInitializerNode) en, flag);
321       return;
322
323       // case Kind.ClassTypeNode:
324       // checkClassTypeNode(md, nametable, (ClassTypeNode) en, flag);
325       // return;
326     }
327   }
328
329   private void checkArrayInitializerNode(MethodDescriptor md, SymbolTable nametable,
330       ArrayInitializerNode ain, boolean flag) {
331
332     for (int i = 0; i < ain.numVarInitializers(); ++i) {
333       checkExpressionNode(md, nametable, ain.getVarInitializer(i), flag);
334     }
335
336   }
337
338   private void checkInstanceOfNode(MethodDescriptor md, SymbolTable nametable, InstanceOfNode tn,
339       boolean flag) {
340     checkExpressionNode(md, nametable, tn.getExpr(), flag);
341   }
342
343   private void checkTertiaryNode(MethodDescriptor md, SymbolTable nametable, TertiaryNode tn,
344       boolean flag) {
345     checkExpressionNode(md, nametable, tn.getCond(), flag);
346     checkExpressionNode(md, nametable, tn.getTrueExpr(), flag);
347     checkExpressionNode(md, nametable, tn.getFalseExpr(), flag);
348   }
349
350   private void checkOpNode(MethodDescriptor md, SymbolTable nametable, OpNode on, boolean flag) {
351
352     checkExpressionNode(md, nametable, on.getLeft(), flag);
353     if (on.getRight() != null) {
354       checkExpressionNode(md, nametable, on.getRight(), flag);
355     }
356
357   }
358
359   private void checkMethodInvokeNode(MethodDescriptor md, SymbolTable nametable,
360       MethodInvokeNode min, boolean flag) {
361     for (int i = 0; i < min.numArgs(); i++) {
362       ExpressionNode en = min.getArg(i);
363       checkExpressionNode(md, nametable, en, flag);
364     }
365
366     if (min.getExpression() != null) {
367       checkExpressionNode(md, nametable, min.getExpression(), flag);
368     }
369
370     if (flag) {
371       annotatedMDSet.add(min.getMethod());
372     }
373
374     Set<MethodDescriptor> mdSet = caller2calleeSet.get(md);
375     if (mdSet == null) {
376       mdSet = new HashSet<MethodDescriptor>();
377       caller2calleeSet.put(md, mdSet);
378     }
379     mdSet.add(min.getMethod());
380
381   }
382
383   private void checkArrayAccessNode(MethodDescriptor md, SymbolTable nametable,
384       ArrayAccessNode aan, boolean flag) {
385
386     ExpressionNode left = aan.getExpression();
387     checkExpressionNode(md, nametable, left, flag);
388     checkExpressionNode(md, nametable, aan.getIndex(), flag);
389
390   }
391
392   private void checkFieldAccessNode(MethodDescriptor md, SymbolTable nametable,
393       FieldAccessNode fan, boolean flag) {
394     ExpressionNode left = fan.getExpression();
395     checkExpressionNode(md, nametable, left, flag);
396   }
397
398   private void checkCreateObjectNode(MethodDescriptor md, SymbolTable nametable,
399       CreateObjectNode con, boolean flag) {
400
401     for (int i = 0; i < con.numArgs(); i++) {
402       ExpressionNode en = con.getArg(i);
403       checkExpressionNode(md, nametable, en, flag);
404     }
405
406   }
407
408   private void checkCastNode(MethodDescriptor md, SymbolTable nametable, CastNode cn, boolean flag) {
409     ExpressionNode en = cn.getExpression();
410     checkExpressionNode(md, nametable, en, flag);
411   }
412
413   private void checkAssignmentNode(MethodDescriptor md, SymbolTable nametable, AssignmentNode an,
414       boolean flag) {
415     boolean postinc = true;
416
417     if (an.getOperation().getBaseOp() == null
418         || (an.getOperation().getBaseOp().getOp() != Operation.POSTINC && an.getOperation()
419             .getBaseOp().getOp() != Operation.POSTDEC))
420       postinc = false;
421
422     if (!postinc) {
423       checkExpressionNode(md, nametable, an.getSrc(), flag);
424     }
425
426     checkExpressionNode(md, nametable, an.getDest(), flag);
427
428   }
429
430 }