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