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