1 package Analysis.SSJava;
3 import java.util.HashSet;
4 import java.util.Hashtable;
5 import java.util.Iterator;
7 import java.util.Vector;
9 import IR.AnnotationDescriptor;
10 import IR.ClassDescriptor;
11 import IR.MethodDescriptor;
14 import IR.SymbolTable;
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;
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;
40 public class MethodAnnotationCheck {
43 SSJavaAnalysis ssjava;
46 Set<MethodDescriptor> annotatedMDSet;
47 Hashtable<MethodDescriptor, Set<MethodDescriptor>> caller2calleeSet;
48 Set<MethodDescriptor> trustWorthyMDSet;
50 public MethodAnnotationCheck(SSJavaAnalysis ssjava, State state, TypeUtil tu) {
54 caller2calleeSet = new Hashtable<MethodDescriptor, Set<MethodDescriptor>>();
55 annotatedMDSet = new HashSet<MethodDescriptor>();
56 trustWorthyMDSet = new HashSet<MethodDescriptor>();
59 public Set<MethodDescriptor> getTrustWorthyMDSet() {
60 return trustWorthyMDSet;
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;
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);
83 for (Iterator iterator = annotatedMDSet.iterator(); iterator.hasNext();) {
84 MethodDescriptor md = (MethodDescriptor) iterator.next();
85 ssjava.addAnnotationRequire(md);
88 Set<Pair> visited = new HashSet<Pair>();
89 Set<MethodDescriptor> tovisit = new HashSet<MethodDescriptor>();
90 tovisit.addAll(annotatedMDSet);
92 while (!tovisit.isEmpty()) {
93 MethodDescriptor callerMD = tovisit.iterator().next();
94 tovisit.remove(callerMD);
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)) {
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);
109 Set<MethodDescriptor> possibleCalleeSet =
110 (Set<MethodDescriptor>) ssjava.getCallGraph().getMethods(calleeMD);
112 for (Iterator iterator2 = possibleCalleeSet.iterator(); iterator2.hasNext();) {
113 MethodDescriptor possibleCallee = (MethodDescriptor) iterator2.next();
115 if (!possibleCallee.isAbstract()) {
116 ssjava.addAnnotationRequire(possibleCallee);
117 tovisit.add(possibleCallee);
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);
142 public void methodAnnoataionInheritanceCheck() {
143 // check If a method is annotated, any method that overrides it should
146 Set<MethodDescriptor> tovisit = new HashSet<MethodDescriptor>();
147 tovisit.addAll(ssjava.getAnnotationRequireSet());
149 while (!tovisit.isEmpty()) {
150 MethodDescriptor md = tovisit.iterator().next();
153 ClassDescriptor cd = md.getClassDesc();
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);
171 // need to check super classess if the current method is inherited from
172 // them, all of ancestor method should be annotated.
174 ClassDescriptor curClassDesc;
175 ClassDescriptor parentClassDesc = cd;
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);
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);
205 private void checkMethodBody(ClassDescriptor cd, MethodDescriptor md) {
206 BlockNode bn = state.getMethodBody(md);
207 checkBlockNode(md, md.getParameterTable(), bn, false);
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)) {
216 throw new Error("Only outermost loop can be the self-stabilizing loop.");
218 annotatedMDSet.add(md);
223 for (int i = 0; i < bn.size(); i++) {
224 BlockStatementNode bsn = bn.get(i);
225 checkBlockStatementNode(md, bn.getVarTable(), bsn, isSSJavaLoop);
230 private void checkBlockStatementNode(MethodDescriptor md, SymbolTable nametable,
231 BlockStatementNode bsn, boolean flag) {
233 switch (bsn.kind()) {
234 case Kind.SubBlockNode:
235 checkSubBlockNode(md, nametable, (SubBlockNode) bsn, flag);
238 case Kind.BlockExpressionNode:
239 checkBlockExpressionNode(md, nametable, (BlockExpressionNode) bsn, flag);
242 case Kind.DeclarationNode:
243 checkDeclarationNode(md, nametable, (DeclarationNode) bsn, flag);
246 case Kind.IfStatementNode:
247 checkIfStatementNode(md, nametable, (IfStatementNode) bsn, flag);
251 checkLoopNode(md, nametable, (LoopNode) bsn, flag);
254 case Kind.ReturnNode:
255 checkReturnNode(md, nametable, (ReturnNode) bsn, flag);
258 case Kind.SwitchStatementNode:
259 checkSwitchStatementNode(md, nametable, (SwitchStatementNode) bsn, flag);
265 private void checkSwitchStatementNode(MethodDescriptor md, SymbolTable nametable,
266 SwitchStatementNode ssn, boolean flag) {
268 checkExpressionNode(md, nametable, ssn.getCondition(), flag);
270 BlockNode sbn = ssn.getSwitchBody();
271 for (int i = 0; i < sbn.size(); i++) {
272 checkBlockNode(md, nametable, ((SwitchBlockNode) sbn.get(i)).getSwitchBlockStatement(), flag);
277 private void checkDeclarationNode(MethodDescriptor md, SymbolTable nametable, DeclarationNode dn,
279 if (dn.getExpression() != null) {
280 checkExpressionNode(md, nametable, dn.getExpression(), flag);
284 private void checkReturnNode(MethodDescriptor md, SymbolTable nametable, ReturnNode rn,
286 if (rn.getReturnExpression() != null) {
287 if (md.getReturnType() != null) {
288 checkExpressionNode(md, nametable, rn.getReturnExpression(), flag);
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);
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);
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);
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);
322 private void checkSubBlockNode(MethodDescriptor md, SymbolTable nametable, SubBlockNode sbn,
324 checkBlockNode(md, nametable.getParent(), sbn.getBlockNode(), flag);
327 private void checkBlockExpressionNode(MethodDescriptor md, SymbolTable nametable,
328 BlockExpressionNode ben, boolean flag) {
329 checkExpressionNode(md, nametable, ben.getExpression(), flag);
332 private void checkExpressionNode(MethodDescriptor md, SymbolTable nametable, ExpressionNode en,
335 case Kind.AssignmentNode:
336 checkAssignmentNode(md, nametable, (AssignmentNode) en, flag);
340 checkCastNode(md, nametable, (CastNode) en, flag);
343 case Kind.CreateObjectNode:
344 checkCreateObjectNode(md, nametable, (CreateObjectNode) en, flag);
347 case Kind.FieldAccessNode:
348 checkFieldAccessNode(md, nametable, (FieldAccessNode) en, flag);
351 case Kind.ArrayAccessNode:
352 checkArrayAccessNode(md, nametable, (ArrayAccessNode) en, flag);
355 // case Kind.LiteralNode:
356 // checkLiteralNode(md, nametable, (LiteralNode) en, flag);
359 case Kind.MethodInvokeNode:
360 checkMethodInvokeNode(md, nametable, (MethodInvokeNode) en, flag);
363 // case Kind.NameNode:
364 // checkNameNode(md, nametable, (NameNode) en, flag);
368 checkOpNode(md, nametable, (OpNode) en, flag);
371 // case Kind.OffsetNode:
372 // checkOffsetNode(md, nametable, (OffsetNode) en, flag);
375 case Kind.TertiaryNode:
376 checkTertiaryNode(md, nametable, (TertiaryNode) en, flag);
379 case Kind.InstanceOfNode:
380 checkInstanceOfNode(md, nametable, (InstanceOfNode) en, flag);
383 case Kind.ArrayInitializerNode:
384 checkArrayInitializerNode(md, nametable, (ArrayInitializerNode) en, flag);
387 // case Kind.ClassTypeNode:
388 // checkClassTypeNode(md, nametable, (ClassTypeNode) en, flag);
393 private void checkArrayInitializerNode(MethodDescriptor md, SymbolTable nametable,
394 ArrayInitializerNode ain, boolean flag) {
396 for (int i = 0; i < ain.numVarInitializers(); ++i) {
397 checkExpressionNode(md, nametable, ain.getVarInitializer(i), flag);
402 private void checkInstanceOfNode(MethodDescriptor md, SymbolTable nametable, InstanceOfNode tn,
404 checkExpressionNode(md, nametable, tn.getExpr(), flag);
407 private void checkTertiaryNode(MethodDescriptor md, SymbolTable nametable, TertiaryNode tn,
409 checkExpressionNode(md, nametable, tn.getCond(), flag);
410 checkExpressionNode(md, nametable, tn.getTrueExpr(), flag);
411 checkExpressionNode(md, nametable, tn.getFalseExpr(), flag);
414 private void checkOpNode(MethodDescriptor md, SymbolTable nametable, OpNode on, boolean flag) {
416 checkExpressionNode(md, nametable, on.getLeft(), flag);
417 if (on.getRight() != null) {
418 checkExpressionNode(md, nametable, on.getRight(), flag);
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);
430 if (min.getExpression() != null) {
431 checkExpressionNode(md, nametable, min.getExpression(), flag);
435 annotatedMDSet.add(min.getMethod());
438 Set<MethodDescriptor> mdSet = caller2calleeSet.get(md);
440 mdSet = new HashSet<MethodDescriptor>();
441 caller2calleeSet.put(md, mdSet);
443 mdSet.add(min.getMethod());
447 private void checkArrayAccessNode(MethodDescriptor md, SymbolTable nametable,
448 ArrayAccessNode aan, boolean flag) {
450 ExpressionNode left = aan.getExpression();
451 checkExpressionNode(md, nametable, left, flag);
452 checkExpressionNode(md, nametable, aan.getIndex(), flag);
456 private void checkFieldAccessNode(MethodDescriptor md, SymbolTable nametable,
457 FieldAccessNode fan, boolean flag) {
458 ExpressionNode left = fan.getExpression();
459 checkExpressionNode(md, nametable, left, flag);
462 private void checkCreateObjectNode(MethodDescriptor md, SymbolTable nametable,
463 CreateObjectNode con, boolean flag) {
465 for (int i = 0; i < con.numArgs(); i++) {
466 ExpressionNode en = con.getArg(i);
467 checkExpressionNode(md, nametable, en, flag);
472 private void checkCastNode(MethodDescriptor md, SymbolTable nametable, CastNode cn, boolean flag) {
473 ExpressionNode en = cn.getExpression();
474 checkExpressionNode(md, nametable, en, flag);
477 private void checkAssignmentNode(MethodDescriptor md, SymbolTable nametable, AssignmentNode an,
479 boolean postinc = true;
481 if (an.getOperation().getBaseOp() == null
482 || (an.getOperation().getBaseOp().getOp() != Operation.POSTINC && an.getOperation()
483 .getBaseOp().getOp() != Operation.POSTDEC))
487 checkExpressionNode(md, nametable, an.getSrc(), flag);
490 checkExpressionNode(md, nametable, an.getDest(), flag);