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