changes: 1) refactoring codes 2) forgot to implement ownsership checking in the flow...
[IRC.git] / Robust / src / Analysis / SSJava / LinearTypeCheck.java
1 package Analysis.SSJava;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.Comparator;
6 import java.util.HashSet;
7 import java.util.Hashtable;
8 import java.util.Iterator;
9 import java.util.List;
10 import java.util.Set;
11 import java.util.Vector;
12
13 import Analysis.Liveness;
14 import IR.AnnotationDescriptor;
15 import IR.ClassDescriptor;
16 import IR.FieldDescriptor;
17 import IR.MethodDescriptor;
18 import IR.Operation;
19 import IR.State;
20 import IR.SymbolTable;
21 import IR.TypeDescriptor;
22 import IR.VarDescriptor;
23 import IR.Flat.FKind;
24 import IR.Flat.FlatMethod;
25 import IR.Flat.FlatNode;
26 import IR.Flat.FlatOpNode;
27 import IR.Flat.TempDescriptor;
28 import IR.Tree.ArrayAccessNode;
29 import IR.Tree.ArrayInitializerNode;
30 import IR.Tree.AssignmentNode;
31 import IR.Tree.BlockExpressionNode;
32 import IR.Tree.BlockNode;
33 import IR.Tree.BlockStatementNode;
34 import IR.Tree.CastNode;
35 import IR.Tree.CreateObjectNode;
36 import IR.Tree.DeclarationNode;
37 import IR.Tree.ExpressionNode;
38 import IR.Tree.FieldAccessNode;
39 import IR.Tree.IfStatementNode;
40 import IR.Tree.Kind;
41 import IR.Tree.LoopNode;
42 import IR.Tree.MethodInvokeNode;
43 import IR.Tree.NameNode;
44 import IR.Tree.OffsetNode;
45 import IR.Tree.OpNode;
46 import IR.Tree.ReturnNode;
47 import IR.Tree.SubBlockNode;
48 import IR.Tree.SwitchBlockNode;
49 import IR.Tree.SwitchStatementNode;
50 import IR.Tree.SynchronizedNode;
51 import IR.Tree.TertiaryNode;
52 import IR.Tree.TreeNode;
53
54 public class LinearTypeCheck {
55
56   State state;
57   SSJavaAnalysis ssjava;
58   String needToNullify = null;
59   TreeNode prevAssignNode;
60
61   Set<TreeNode> linearTypeCheckSet;
62
63   Hashtable<TreeNode, FlatMethod> mapTreeNode2FlatMethod;
64
65   Set<MethodDescriptor> delegateThisMethodSet;
66
67   Liveness liveness;
68
69   boolean deterministic = true;
70
71   public LinearTypeCheck(SSJavaAnalysis ssjava, State state) {
72     this.ssjava = ssjava;
73     this.state = state;
74     this.linearTypeCheckSet = new HashSet<TreeNode>();
75     this.mapTreeNode2FlatMethod = new Hashtable<TreeNode, FlatMethod>();
76     this.delegateThisMethodSet = new HashSet<MethodDescriptor>();
77     this.liveness = new Liveness();
78   }
79
80   public void linearTypeCheck() {
81
82     // first, parsing DELEGATE annotation from method declarations
83     Iterator it = state.getClassSymbolTable().getDescriptorsIterator();
84     while (it.hasNext()) {
85       ClassDescriptor cd = (ClassDescriptor) it.next();
86       for (Iterator method_it = cd.getMethods(); method_it.hasNext();) {
87         MethodDescriptor md = (MethodDescriptor) method_it.next();
88         parseAnnotations(md);
89       }
90     }
91
92     // second, check the linear type
93     if (deterministic) {
94
95       SymbolTable classtable = state.getClassSymbolTable();
96
97       List<ClassDescriptor> toanalyzeList = new ArrayList<ClassDescriptor>();
98       List<MethodDescriptor> toanalyzeMethodList = new ArrayList<MethodDescriptor>();
99
100       toanalyzeList.addAll(classtable.getValueSet());
101       Collections.sort(toanalyzeList, new Comparator<ClassDescriptor>() {
102         public int compare(ClassDescriptor o1, ClassDescriptor o2) {
103           return o1.getClassName().compareTo(o2.getClassName());
104         }
105       });
106
107       for (int i = 0; i < toanalyzeList.size(); i++) {
108         ClassDescriptor cd = toanalyzeList.get(i);
109
110         SymbolTable methodtable = cd.getMethodTable();
111         toanalyzeMethodList.clear();
112         toanalyzeMethodList.addAll(methodtable.getValueSet());
113         Collections.sort(toanalyzeMethodList, new Comparator<MethodDescriptor>() {
114           public int compare(MethodDescriptor o1, MethodDescriptor o2) {
115             return o1.getSymbol().compareTo(o2.getSymbol());
116           }
117         });
118
119         for (int mdIdx = 0; mdIdx < toanalyzeMethodList.size(); mdIdx++) {
120           MethodDescriptor md = toanalyzeMethodList.get(mdIdx);
121           if (ssjava.needToCheckLinearType(md)) {
122             checkMethodBody(cd, md);
123           }
124         }
125
126       }
127
128     } else {
129       it = state.getClassSymbolTable().getDescriptorsIterator();
130       while (it.hasNext()) {
131         ClassDescriptor cd = (ClassDescriptor) it.next();
132         for (Iterator method_it = cd.getMethods(); method_it.hasNext();) {
133           MethodDescriptor md = (MethodDescriptor) method_it.next();
134           checkMethodBody(cd, md);
135         }
136       }
137     }
138
139     // third, check if original references are destroyed after creating new
140     // alias
141
142     for (Iterator<TreeNode> iterator = linearTypeCheckSet.iterator(); iterator.hasNext();) {
143       TreeNode tn = iterator.next();
144       Set<FlatNode> fnSet = ssjava.getBuildFlat().getFlatNodeSet(tn);
145       if (fnSet != null) {
146         for (Iterator iterator2 = fnSet.iterator(); iterator2.hasNext();) {
147           FlatNode fn = (FlatNode) iterator2.next();
148           if (isLiveOut(tn, fn)) {
149             throw new Error(
150                 "Local variable '"
151                     + tn.printNode(0)
152                     + "', which is read by a method, should be destroyed after introducing new alias at "
153                     + mapTreeNode2FlatMethod.get(tn).getMethod().getClassDesc().getSourceFileName()
154                     + "::" + tn.getNumLine());
155           }
156
157         }
158       }
159
160     }
161
162   }
163
164   private boolean isLiveOut(TreeNode tn, FlatNode fn) {
165     Set<TempDescriptor> liveOutTemp = liveness.getLiveOutTemps(mapTreeNode2FlatMethod.get(tn), fn);
166     if (fn.kind() == FKind.FlatOpNode) {
167       FlatOpNode fon = (FlatOpNode) fn;
168       return liveOutTemp.contains(fon.getLeft());
169     }
170     return false;
171   }
172
173   private void parseAnnotations(MethodDescriptor md) {
174
175     // method annotation parsing
176     Vector<AnnotationDescriptor> methodAnnotations = md.getModifiers().getAnnotations();
177     if (methodAnnotations != null) {
178       for (int i = 0; i < methodAnnotations.size(); i++) {
179         AnnotationDescriptor an = methodAnnotations.elementAt(i);
180         if (an.getMarker().equals(ssjava.DELEGATETHIS)) {
181           delegateThisMethodSet.add(md);
182           md.getThis().getType().setExtension(new SSJavaType(true));
183         }
184       }
185     }
186
187     // paramter annotation parsing
188     for (int i = 0; i < md.numParameters(); i++) {
189       // process annotations on method parameters
190       VarDescriptor vd = (VarDescriptor) md.getParameter(i);
191
192       Vector<AnnotationDescriptor> annotationVec = vd.getType().getAnnotationMarkers();
193
194       for (int anIdx = 0; anIdx < annotationVec.size(); anIdx++) {
195         AnnotationDescriptor ad = annotationVec.elementAt(anIdx);
196         if (ad.getMarker().equals(SSJavaAnalysis.DELEGATE)) {
197           SSJavaType locationType = new SSJavaType(true);
198           vd.getType().setExtension(locationType);
199         }
200       }
201     }
202   }
203
204   private void checkMethodBody(ClassDescriptor cd, MethodDescriptor md) {
205     if (state.SSJAVADEBUG) {
206       System.out.println("SSJAVA: Linear Type Checking: " + md);
207     }
208     BlockNode bn = state.getMethodBody(md);
209     checkBlockNode(md, md.getParameterTable(), bn);
210   }
211
212   private void checkBlockNode(MethodDescriptor md, SymbolTable nametable, BlockNode bn) {
213     for (int i = 0; i < bn.size(); i++) {
214       BlockStatementNode bsn = bn.get(i);
215       checkBlockStatementNode(md, bn.getVarTable(), bsn);
216     }
217   }
218
219   private void checkBlockStatementNode(MethodDescriptor md, SymbolTable nametable,
220       BlockStatementNode bsn) {
221
222     if (needToNullify != null) {
223       if (!checkNullifying(bsn)) {
224         throw new Error(
225             "Reference field '"
226                 + needToNullify
227                 + "', which is read by a method, should be assigned to null before executing any following statement of the reference copy statement at "
228                 + md.getClassDesc().getSourceFileName() + "::" + prevAssignNode.getNumLine());
229       }
230     }
231
232     switch (bsn.kind()) {
233
234     case Kind.BlockExpressionNode:
235       checkBlockExpressionNode(md, nametable, (BlockExpressionNode) bsn);
236       return;
237
238     case Kind.DeclarationNode:
239       checkDeclarationNode(md, nametable, (DeclarationNode) bsn);
240       return;
241
242     case Kind.IfStatementNode:
243       checkIfStatementNode(md, nametable, (IfStatementNode) bsn);
244       return;
245
246     case Kind.SwitchStatementNode:
247       checkSwitchStatementNode(md, nametable, (SwitchStatementNode) bsn);
248       return;
249
250     case Kind.LoopNode:
251       checkLoopNode(md, nametable, (LoopNode) bsn);
252       return;
253
254     case Kind.ReturnNode:
255       checkReturnNode(md, nametable, (ReturnNode) bsn);
256       return;
257
258     case Kind.SubBlockNode:
259       checkSubBlockNode(md, nametable, (SubBlockNode) bsn);
260       return;
261
262     case Kind.SynchronizedNode:
263       checkSynchronizedNode(md, nametable, (SynchronizedNode) bsn);
264       return;
265     }
266
267   }
268
269   private void checkSynchronizedNode(MethodDescriptor md, SymbolTable nametable,
270       SynchronizedNode sbn) {
271     checkBlockNode(md, nametable, sbn.getBlockNode());
272     // todo this could be Object
273     checkExpressionNode(md, nametable, sbn.getExpr());
274   }
275
276   private void checkReturnNode(MethodDescriptor md, SymbolTable nametable, ReturnNode rn) {
277     if (rn.getReturnExpression() != null) {
278       checkExpressionNode(md, nametable, rn.getReturnExpression());
279     }
280   }
281
282   private void checkSubBlockNode(MethodDescriptor md, SymbolTable nametable, SubBlockNode sbn) {
283     checkBlockNode(md, nametable, sbn.getBlockNode());
284   }
285
286   private void checkIfStatementNode(MethodDescriptor md, SymbolTable nametable, IfStatementNode isn) {
287     checkExpressionNode(md, nametable, isn.getCondition());
288     checkBlockNode(md, nametable, isn.getTrueBlock());
289     if (isn.getFalseBlock() != null)
290       checkBlockNode(md, nametable, isn.getFalseBlock());
291   }
292
293   private void checkSwitchStatementNode(MethodDescriptor md, SymbolTable nametable,
294       SwitchStatementNode ssn) {
295
296     checkExpressionNode(md, nametable, ssn.getCondition());
297
298     BlockNode sbn = ssn.getSwitchBody();
299     for (int i = 0; i < sbn.size(); i++) {
300       checkSwitchBlockNode(md, nametable, (SwitchBlockNode) sbn.get(i));
301     }
302   }
303
304   private void checkSwitchBlockNode(MethodDescriptor md, SymbolTable nametable, SwitchBlockNode sbn) {
305     checkBlockNode(md, nametable, sbn.getSwitchBlockStatement());
306   }
307
308   private void checkBlockExpressionNode(MethodDescriptor md, SymbolTable nametable,
309       BlockExpressionNode ben) {
310     checkExpressionNode(md, nametable, ben.getExpression());
311   }
312
313   private void checkExpressionNode(MethodDescriptor md, SymbolTable nametable, ExpressionNode en) {
314     switch (en.kind()) {
315     case Kind.AssignmentNode:
316       checkAssignmentNode(md, nametable, (AssignmentNode) en);
317       return;
318
319     case Kind.CastNode:
320       checkCastNode(md, nametable, (CastNode) en);
321       return;
322
323     case Kind.CreateObjectNode:
324       checkCreateObjectNode(md, nametable, (CreateObjectNode) en);
325       return;
326
327     case Kind.FieldAccessNode:
328       checkFieldAccessNode(md, nametable, (FieldAccessNode) en);
329       return;
330
331     case Kind.ArrayAccessNode:
332       checkArrayAccessNode(md, nametable, (ArrayAccessNode) en);
333       return;
334
335       // case Kind.LiteralNode:
336       // checkLiteralNode(md, nametable, (LiteralNode) en);
337       // return;
338
339     case Kind.MethodInvokeNode:
340       checkMethodInvokeNode(md, nametable, (MethodInvokeNode) en);
341       return;
342
343     case Kind.NameNode:
344       checkNameNode(md, nametable, (NameNode) en);
345       return;
346
347     case Kind.OpNode:
348       checkOpNode(md, nametable, (OpNode) en);
349       return;
350
351     case Kind.OffsetNode:
352       checkOffsetNode(md, nametable, (OffsetNode) en);
353       return;
354
355     case Kind.TertiaryNode:
356       checkTertiaryNode(md, nametable, (TertiaryNode) en);
357       return;
358
359       // case Kind.InstanceOfNode:
360       // checkInstanceOfNode(md, nametable, (InstanceOfNode) en);
361       // return;
362
363       // case Kind.ArrayInitializerNode:
364       // checkArrayInitializerNode(md, nametable, (ArrayInitializerNode) en);
365       // return;
366
367       // case Kind.ClassTypeNode:
368       // checkClassTypeNode(md, nametable, (ClassTypeNode) ens);
369       // return;
370     }
371   }
372
373   private void checkTertiaryNode(MethodDescriptor md, SymbolTable nametable, TertiaryNode tn) {
374     checkExpressionNode(md, nametable, tn.getCond());
375     checkExpressionNode(md, nametable, tn.getTrueExpr());
376     checkExpressionNode(md, nametable, tn.getFalseExpr());
377   }
378
379   private void checkOffsetNode(MethodDescriptor md, SymbolTable nametable, OffsetNode en) {
380     // TODO Auto-generated method stub
381
382   }
383
384   private void checkOpNode(MethodDescriptor md, SymbolTable nametable, OpNode en) {
385     // TODO Auto-generated method stub
386
387   }
388
389   private void checkNameNode(MethodDescriptor md, SymbolTable nametable, NameNode en) {
390     // TODO Auto-generated method stub
391
392   }
393
394   private boolean isOwned(VarDescriptor varDesc) {
395     if (varDesc.getType().getExtension() != null) {
396       SSJavaType locationType = (SSJavaType) varDesc.getType().getExtension();
397       return locationType.isOwned();
398     }
399     return false;
400   }
401
402   private void checkMethodInvokeNode(MethodDescriptor md, SymbolTable nametable,
403       MethodInvokeNode min) {
404
405     MethodDescriptor calleeMethodDesc = min.getMethod();
406
407     // check delegate_this annotation
408     // only method that owns itself 'THIS' can call method with delegate_this
409     // annotation
410
411     if (delegateThisMethodSet.contains(calleeMethodDesc)) {
412
413       if (min.getBaseName() == null) {
414         if (!delegateThisMethodSet.contains(md)) {
415           throw new Error("Caller does not own the 'THIS' argument at " + md.getClassDesc() + "::"
416               + min.getNumLine());
417         }
418       } else {
419         VarDescriptor baseVar = (VarDescriptor) nametable.get(min.getBaseName().getIdentifier());
420         if (!isOwned(baseVar)) {
421           throw new Error("Caller does not own the 'THIS' argument at " + md.getClassDesc() + "::"
422               + min.getNumLine());
423         }
424       }
425     }
426
427     // check delegate parameter annotation
428     for (int i = 0; i < min.numArgs(); i++) {
429       ExpressionNode argNode = min.getArg(i);
430
431       TypeDescriptor paramType = calleeMethodDesc.getParamType(i);
432
433       if (isReference(argNode.getType()) && !argNode.getType().isNull()) {
434
435         boolean isParamOwnedByCallee = false;
436         if (paramType.getExtension() != null) {
437           SSJavaType locationType = (SSJavaType) paramType.getExtension();
438           isParamOwnedByCallee = locationType.isOwned();
439         }
440
441         TypeDescriptor argType = getTypeDescriptor(argNode);
442
443         if (isParamOwnedByCallee) {
444
445           // cannot pass field reference through ownership transition
446           if (isField(argNode)) {
447             throw new Error("Caller cannot transfer its ownership of the field reference at "
448                 + md.getClassDesc() + "::" + min.getNumLine());
449           }
450
451           // method expects that argument is owned by caller
452           SSJavaType locationType = (SSJavaType) argType.getExtension();
453
454           if (locationType == null || !locationType.isOwned()) {
455             throw new Error("Caller passes an argument not owned by itself at " + md.getClassDesc()
456                 + "::" + min.getNumLine());
457           }
458
459           // delegated arg is no longer to be available from here
460           linearTypeCheckSet.add(argNode);
461           mapTreeNode2FlatMethod.put(argNode, state.getMethodFlat(md));
462         }
463
464       }
465     }
466
467   }
468
469   private void checkArrayAccessNode(MethodDescriptor md, SymbolTable nametable, ArrayAccessNode en) {
470     // TODO Auto-generated method stub
471
472   }
473
474   private void checkFieldAccessNode(MethodDescriptor md, SymbolTable nametable, FieldAccessNode fan) {
475
476   }
477
478   private void checkCreateObjectNode(MethodDescriptor md, SymbolTable nametable,
479       CreateObjectNode con) {
480
481     TypeDescriptor[] tdarray = new TypeDescriptor[con.numArgs()];
482     for (int i = 0; i < con.numArgs(); i++) {
483       ExpressionNode en = con.getArg(i);
484       checkExpressionNode(md, nametable, en);
485       tdarray[i] = en.getType();
486     }
487
488     if ((con.getArrayInitializer() != null)) {
489       checkArrayInitializerNode(md, nametable, con.getArrayInitializer());
490     }
491
492     // the current method owns a instance that it makes inside
493     SSJavaType locationType = new SSJavaType(true);
494     con.getType().setExtension(locationType);
495
496   }
497
498   private void checkArrayInitializerNode(MethodDescriptor md, SymbolTable nametable,
499       ArrayInitializerNode arrayInitializer) {
500     // TODO Auto-generated method stub
501
502   }
503
504   private void checkCastNode(MethodDescriptor md, SymbolTable nametable, CastNode cn) {
505     ExpressionNode en = cn.getExpression();
506     checkExpressionNode(md, nametable, en);
507   }
508
509   private boolean checkNullifying(BlockStatementNode bsn) {
510
511     if (bsn.kind() == Kind.BlockExpressionNode) {
512       ExpressionNode en = ((BlockExpressionNode) bsn).getExpression();
513       if (en.kind() == Kind.AssignmentNode) {
514         AssignmentNode an = (AssignmentNode) en;
515
516         String destName = an.getDest().printNode(0);
517         if (destName.startsWith("this.")) {
518           destName = destName.substring(5);
519         }
520
521         if (an.getSrc().getType().isNull() && destName.equals(needToNullify)) {
522           needToNullify = null;
523           return true;
524         }
525       }
526     }
527
528     return false;
529   }
530
531   private void checkLoopNode(MethodDescriptor md, SymbolTable nametable, LoopNode ln) {
532     if (ln.getType() == LoopNode.WHILELOOP || ln.getType() == LoopNode.DOWHILELOOP) {
533       checkExpressionNode(md, nametable, ln.getCondition());
534       checkBlockNode(md, nametable, ln.getBody());
535     } else {
536       // For loop case
537       /* Link in the initializer naming environment */
538       BlockNode bn = ln.getInitializer();
539       for (int i = 0; i < bn.size(); i++) {
540         BlockStatementNode bsn = bn.get(i);
541         checkBlockStatementNode(md, bn.getVarTable(), bsn);
542       }
543       // check the condition
544       checkExpressionNode(md, bn.getVarTable(), ln.getCondition());
545       checkBlockNode(md, bn.getVarTable(), ln.getBody());
546       checkBlockNode(md, bn.getVarTable(), ln.getUpdate());
547     }
548   }
549
550   private void checkAssignmentNode(MethodDescriptor md, SymbolTable nametable, AssignmentNode an) {
551
552     boolean postinc = true;
553     if (an.getOperation().getBaseOp() == null
554         || (an.getOperation().getBaseOp().getOp() != Operation.POSTINC && an.getOperation()
555             .getBaseOp().getOp() != Operation.POSTDEC))
556       postinc = false;
557
558     if (!postinc) {
559       checkExpressionNode(md, nametable, an.getSrc());
560       if (isReference(an.getSrc().getType()) && isReference(an.getDest().getType())) {
561         checkAlias(md, an, an.getSrc());
562       }
563
564     }
565
566   }
567
568   private boolean isFieldOfClass(ClassDescriptor classDesc, String varName) {
569     return classDesc.getFieldTable().contains(varName);
570   }
571
572   private boolean isCreatingAlias(ExpressionNode en) {
573
574     int kind = en.kind();
575     if (kind == Kind.NameNode || kind == Kind.ArrayAccessNode || kind == Kind.FieldAccessNode) {
576       return true;
577     }
578     return false;
579
580   }
581
582   private TypeDescriptor getTypeDescriptor(ExpressionNode en) {
583     if (en.kind() == Kind.NameNode) {
584       NameNode nn = (NameNode) en;
585       if (nn.getField() != null) {
586         return nn.getVar().getType();
587       } else if (nn.getVar() != null) {
588         return nn.getVar().getType();
589       } else {
590         return getTypeDescriptor(nn.getExpression());
591       }
592     } else if (en.kind() == Kind.FieldAccessNode) {
593       FieldAccessNode fan = (FieldAccessNode) en;
594       return getTypeDescriptor(fan.getExpression());
595     } else if (en.kind() == Kind.CreateObjectNode) {
596       CreateObjectNode con = (CreateObjectNode) en;
597       return con.getType();
598     } else if (en.kind() == Kind.ArrayAccessNode) {
599       ArrayAccessNode aan = (ArrayAccessNode) en;
600       return aan.getExpression().getType();
601     }
602
603     return null;
604   }
605
606   private FieldDescriptor getFieldDescriptorFromExpressionNode(ExpressionNode en) {
607
608     if (en.kind() == Kind.NameNode) {
609       NameNode nn = (NameNode) en;
610       if (nn.getField() != null) {
611         return nn.getField();
612       }
613
614       if (nn.getName() != null && nn.getName().getBase() != null) {
615         return getFieldDescriptorFromExpressionNode(nn.getExpression());
616       }
617
618     } else if (en.kind() == Kind.FieldAccessNode) {
619       FieldAccessNode fan = (FieldAccessNode) en;
620       return fan.getField();
621     }
622
623     return null;
624   }
625
626   private boolean isField(ExpressionNode en) {
627
628     if (en.kind() == Kind.NameNode) {
629       NameNode nn = (NameNode) en;
630       if (nn.getField() != null) {
631         return true;
632       }
633
634       if (nn.getName() != null && nn.getName().getBase() != null) {
635         return true;
636       }
637
638     } else if (en.kind() == Kind.FieldAccessNode) {
639       return true;
640     }
641     return false;
642   }
643
644   private void checkAlias(MethodDescriptor md, TreeNode node, ExpressionNode src) {
645
646     if (src.kind() == Kind.NameNode) {
647
648       NameNode nn = (NameNode) src;
649
650       if (nn.getField() != null) {
651         needToNullify = nn.getField().getSymbol();
652         prevAssignNode = node;
653       } else if (nn.getExpression() != null) {
654         if (nn.getExpression() instanceof FieldAccessNode) {
655           FieldAccessNode fan = (FieldAccessNode) nn.getExpression();
656           needToNullify = fan.printNode(0);
657           prevAssignNode = node;
658         }
659       } else {
660         // local variable case
661         linearTypeCheckSet.add(src);
662         mapTreeNode2FlatMethod.put(src, state.getMethodFlat(md));
663       }
664     } else if (src.kind() == Kind.FieldAccessNode) {
665       FieldAccessNode fan = (FieldAccessNode) src;
666       needToNullify = fan.printNode(0);
667       if (needToNullify.startsWith("this.")) {
668         needToNullify = needToNullify.substring(5);
669       }
670       prevAssignNode = node;
671     } else if (src.kind() == Kind.ArrayAccessNode) {
672       TypeDescriptor srcType = src.getType();
673       if (srcType.isPtr() && !srcType.isString()) {
674         throw new Error(
675             "Not allowed to create an alias to the middle of the multidimensional array at "
676                 + md.getClassDesc().getSourceFileName() + "::" + node.getNumLine());
677       }
678     } else if (src.kind() == Kind.CreateObjectNode || src.kind() == Kind.MethodInvokeNode
679         || src.kind() == Kind.ArrayInitializerNode || src.kind() == Kind.LiteralNode) {
680       if (node.kind() == Kind.DeclarationNode) {
681         DeclarationNode dn = (DeclarationNode) node;
682         dn.getVarDescriptor().getType().setExtension(new SSJavaType(true));
683       }
684     } else {
685       throw new Error("Not allowed this type of assignment at "
686           + md.getClassDesc().getSourceFileName() + "::" + node.getNumLine());
687     }
688
689     if (isCreatingAlias(src)) {
690
691       TypeDescriptor srcType = getTypeDescriptor(src);
692       boolean isSourceOwned = false;
693
694       if (srcType.getExtension() != null) {
695         SSJavaType srcLocationType = (SSJavaType) srcType.getExtension();
696         isSourceOwned = srcLocationType.isOwned();
697
698         if (isSourceOwned) {
699           if (isField(src)) {
700             ssjava.setFieldOnwership(md, getFieldDescriptorFromExpressionNode(src));
701           }
702         }
703
704       } else if (md.isConstructor() && isFieldOfClass(md.getClassDesc(), src.printNode(0))) {
705         isSourceOwned = true;
706         ssjava.setFieldOnwership(md, getFieldDescriptorFromExpressionNode(src));
707       }
708
709       if (node.kind() == Kind.AssignmentNode) {
710         AssignmentNode an = (AssignmentNode) node;
711         if (isField(an.getDest())) {
712           // if instance is not owned by the method, not able to store
713           // instance into field
714           if (!isSourceOwned) {
715             throw new Error(
716                 "Method is not allowed to store an instance not owned by itself into a field at "
717                     + md.getClassDesc().getSourceFileName() + "::" + node.getNumLine());
718           }
719         } else {
720           if (isSourceOwned) {
721             // here, transfer ownership from LHS to RHS when it creates alias
722             TypeDescriptor destType = getTypeDescriptor(an.getDest());
723             destType.setExtension(new SSJavaType(isSourceOwned));
724           }
725         }
726       }
727
728     }
729
730   }
731
732   private void checkDeclarationNode(MethodDescriptor md, SymbolTable nametable, DeclarationNode dn) {
733     if (dn.getExpression() != null) {
734       ExpressionNode src = dn.getExpression();
735       if (isReference(src.getType())) {
736         checkAlias(md, dn, src);
737       }
738     }
739   }
740
741   private boolean isReference(TypeDescriptor td) {
742     if (td.isPtr()) {
743       return true;
744     }
745     return false;
746   }
747
748 }