changes: LayerIDecoder and LayerIIDecoder pass the flow-down rule checking
[IRC.git] / Robust / src / Analysis / SSJava / FlowDownCheck.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.StringTokenizer;
12 import java.util.Vector;
13
14 import Analysis.SSJava.FlowDownCheck.ComparisonResult;
15 import Analysis.SSJava.FlowDownCheck.CompositeLattice;
16 import IR.AnnotationDescriptor;
17 import IR.ClassDescriptor;
18 import IR.Descriptor;
19 import IR.FieldDescriptor;
20 import IR.MethodDescriptor;
21 import IR.NameDescriptor;
22 import IR.Operation;
23 import IR.State;
24 import IR.SymbolTable;
25 import IR.TypeDescriptor;
26 import IR.VarDescriptor;
27 import IR.Tree.ArrayAccessNode;
28 import IR.Tree.AssignmentNode;
29 import IR.Tree.BlockExpressionNode;
30 import IR.Tree.BlockNode;
31 import IR.Tree.BlockStatementNode;
32 import IR.Tree.CastNode;
33 import IR.Tree.CreateObjectNode;
34 import IR.Tree.DeclarationNode;
35 import IR.Tree.ExpressionNode;
36 import IR.Tree.FieldAccessNode;
37 import IR.Tree.IfStatementNode;
38 import IR.Tree.Kind;
39 import IR.Tree.LiteralNode;
40 import IR.Tree.LoopNode;
41 import IR.Tree.MethodInvokeNode;
42 import IR.Tree.NameNode;
43 import IR.Tree.OpNode;
44 import IR.Tree.ReturnNode;
45 import IR.Tree.SubBlockNode;
46 import IR.Tree.SwitchBlockNode;
47 import IR.Tree.SwitchStatementNode;
48 import IR.Tree.SynchronizedNode;
49 import IR.Tree.TertiaryNode;
50 import IR.Tree.TreeNode;
51 import Util.Pair;
52
53 public class FlowDownCheck {
54
55   State state;
56   static SSJavaAnalysis ssjava;
57
58   Set<ClassDescriptor> toanalyze;
59   List<ClassDescriptor> toanalyzeList;
60
61   Set<MethodDescriptor> toanalyzeMethod;
62   List<MethodDescriptor> toanalyzeMethodList;
63
64   // mapping from 'descriptor' to 'composite location'
65   Hashtable<Descriptor, CompositeLocation> d2loc;
66
67   Hashtable<MethodDescriptor, CompositeLocation> md2ReturnLoc;
68   Hashtable<MethodDescriptor, ReturnLocGenerator> md2ReturnLocGen;
69
70   // mapping from 'locID' to 'class descriptor'
71   Hashtable<String, ClassDescriptor> fieldLocName2cd;
72
73   boolean deterministic = true;
74
75   public FlowDownCheck(SSJavaAnalysis ssjava, State state) {
76     this.ssjava = ssjava;
77     this.state = state;
78     if (deterministic) {
79       this.toanalyzeList = new ArrayList<ClassDescriptor>();
80     } else {
81       this.toanalyze = new HashSet<ClassDescriptor>();
82     }
83     if (deterministic) {
84       this.toanalyzeMethodList = new ArrayList<MethodDescriptor>();
85     } else {
86       this.toanalyzeMethod = new HashSet<MethodDescriptor>();
87     }
88     this.d2loc = new Hashtable<Descriptor, CompositeLocation>();
89     this.fieldLocName2cd = new Hashtable<String, ClassDescriptor>();
90     this.md2ReturnLoc = new Hashtable<MethodDescriptor, CompositeLocation>();
91     this.md2ReturnLocGen = new Hashtable<MethodDescriptor, ReturnLocGenerator>();
92   }
93
94   public void init() {
95
96     // construct mapping from the location name to the class descriptor
97     // assume that the location name is unique through the whole program
98
99     Set<ClassDescriptor> cdSet = ssjava.getCd2lattice().keySet();
100     for (Iterator iterator = cdSet.iterator(); iterator.hasNext();) {
101       ClassDescriptor cd = (ClassDescriptor) iterator.next();
102       SSJavaLattice<String> lattice = ssjava.getCd2lattice().get(cd);
103       Set<String> fieldLocNameSet = lattice.getKeySet();
104
105       for (Iterator iterator2 = fieldLocNameSet.iterator(); iterator2.hasNext();) {
106         String fieldLocName = (String) iterator2.next();
107         fieldLocName2cd.put(fieldLocName, cd);
108       }
109
110     }
111
112   }
113
114   public boolean toAnalyzeIsEmpty() {
115     if (deterministic) {
116       return toanalyzeList.isEmpty();
117     } else {
118       return toanalyze.isEmpty();
119     }
120   }
121
122   public ClassDescriptor toAnalyzeNext() {
123     if (deterministic) {
124       return toanalyzeList.remove(0);
125     } else {
126       ClassDescriptor cd = toanalyze.iterator().next();
127       toanalyze.remove(cd);
128       return cd;
129     }
130   }
131
132   public void setupToAnalyze() {
133     SymbolTable classtable = state.getClassSymbolTable();
134     if (deterministic) {
135       toanalyzeList.clear();
136       toanalyzeList.addAll(classtable.getValueSet());
137       Collections.sort(toanalyzeList, new Comparator<ClassDescriptor>() {
138         public int compare(ClassDescriptor o1, ClassDescriptor o2) {
139           return o1.getClassName().compareTo(o2.getClassName());
140         }
141       });
142     } else {
143       toanalyze.clear();
144       toanalyze.addAll(classtable.getValueSet());
145     }
146   }
147
148   public void setupToAnalazeMethod(ClassDescriptor cd) {
149
150     SymbolTable methodtable = cd.getMethodTable();
151     if (deterministic) {
152       toanalyzeMethodList.clear();
153       toanalyzeMethodList.addAll(methodtable.getValueSet());
154       Collections.sort(toanalyzeMethodList, new Comparator<MethodDescriptor>() {
155         public int compare(MethodDescriptor o1, MethodDescriptor o2) {
156           return o1.getSymbol().compareTo(o2.getSymbol());
157         }
158       });
159     } else {
160       toanalyzeMethod.clear();
161       toanalyzeMethod.addAll(methodtable.getValueSet());
162     }
163   }
164
165   public boolean toAnalyzeMethodIsEmpty() {
166     if (deterministic) {
167       return toanalyzeMethodList.isEmpty();
168     } else {
169       return toanalyzeMethod.isEmpty();
170     }
171   }
172
173   public MethodDescriptor toAnalyzeMethodNext() {
174     if (deterministic) {
175       return toanalyzeMethodList.remove(0);
176     } else {
177       MethodDescriptor md = toanalyzeMethod.iterator().next();
178       toanalyzeMethod.remove(md);
179       return md;
180     }
181   }
182
183   public void flowDownCheck() {
184
185     // phase 1 : checking declaration node and creating mapping of 'type
186     // desciptor' & 'location'
187     setupToAnalyze();
188
189     while (!toAnalyzeIsEmpty()) {
190       ClassDescriptor cd = toAnalyzeNext();
191
192       if (ssjava.needToBeAnnoated(cd)) {
193
194         ClassDescriptor superDesc = cd.getSuperDesc();
195
196         if (superDesc != null && (!superDesc.getSymbol().equals("Object"))) {
197           checkOrderingInheritance(superDesc, cd);
198         }
199
200         checkDeclarationInClass(cd);
201
202         setupToAnalazeMethod(cd);
203         while (!toAnalyzeMethodIsEmpty()) {
204           MethodDescriptor md = toAnalyzeMethodNext();
205           if (ssjava.needTobeAnnotated(md)) {
206             checkDeclarationInMethodBody(cd, md);
207           }
208         }
209
210       }
211
212     }
213
214     // phase2 : checking assignments
215     setupToAnalyze();
216
217     while (!toAnalyzeIsEmpty()) {
218       ClassDescriptor cd = toAnalyzeNext();
219
220       setupToAnalazeMethod(cd);
221       while (!toAnalyzeMethodIsEmpty()) {
222         MethodDescriptor md = toAnalyzeMethodNext();
223         if (ssjava.needTobeAnnotated(md)) {
224           System.out.println("SSJAVA: Checking assignments: " + md);
225           checkMethodBody(cd, md);
226         }
227       }
228     }
229
230   }
231
232   private void checkOrderingInheritance(ClassDescriptor superCd, ClassDescriptor cd) {
233     // here, we're going to check that sub class keeps same relative orderings
234     // in respect to super class
235
236     SSJavaLattice<String> superLattice = ssjava.getClassLattice(superCd);
237     SSJavaLattice<String> subLattice = ssjava.getClassLattice(cd);
238
239     if (superLattice != null) {
240       // if super class doesn't define lattice, then we don't need to check its
241       // subclass
242       if (subLattice == null) {
243         throw new Error("If a parent class '" + superCd
244             + "' has a ordering lattice, its subclass '" + cd + "' should have one.");
245       }
246
247       Set<Pair<String, String>> superPairSet = superLattice.getOrderingPairSet();
248       Set<Pair<String, String>> subPairSet = subLattice.getOrderingPairSet();
249
250       for (Iterator iterator = superPairSet.iterator(); iterator.hasNext();) {
251         Pair<String, String> pair = (Pair<String, String>) iterator.next();
252
253         if (!subPairSet.contains(pair)) {
254           throw new Error("Subclass '" + cd + "' does not have the relative ordering '"
255               + pair.getSecond() + " < " + pair.getFirst()
256               + "' that is defined by its superclass '" + superCd + "'.");
257         }
258       }
259     }
260
261     MethodLattice<String> superMethodDefaultLattice = ssjava.getMethodDefaultLattice(superCd);
262     MethodLattice<String> subMethodDefaultLattice = ssjava.getMethodDefaultLattice(cd);
263
264     if (superMethodDefaultLattice != null) {
265       if (subMethodDefaultLattice == null) {
266         throw new Error("When a parent class '" + superCd
267             + "' defines a default method lattice, its subclass '" + cd + "' should define one.");
268       }
269
270       Set<Pair<String, String>> superPairSet = superMethodDefaultLattice.getOrderingPairSet();
271       Set<Pair<String, String>> subPairSet = subMethodDefaultLattice.getOrderingPairSet();
272
273       for (Iterator iterator = superPairSet.iterator(); iterator.hasNext();) {
274         Pair<String, String> pair = (Pair<String, String>) iterator.next();
275
276         if (!subPairSet.contains(pair)) {
277           throw new Error("Subclass '" + cd + "' does not have the relative ordering '"
278               + pair.getSecond() + " < " + pair.getFirst()
279               + "' that is defined by its superclass '" + superCd
280               + "' in the method default lattice.");
281         }
282       }
283
284     }
285
286   }
287
288   public Hashtable getMap() {
289     return d2loc;
290   }
291
292   private void checkDeclarationInMethodBody(ClassDescriptor cd, MethodDescriptor md) {
293     BlockNode bn = state.getMethodBody(md);
294
295     // first, check annotations on method parameters
296     List<CompositeLocation> paramList = new ArrayList<CompositeLocation>();
297     for (int i = 0; i < md.numParameters(); i++) {
298       // process annotations on method parameters
299       VarDescriptor vd = (VarDescriptor) md.getParameter(i);
300       assignLocationOfVarDescriptor(vd, md, md.getParameterTable(), bn);
301       paramList.add(d2loc.get(vd));
302     }
303
304     // second, check return location annotation
305     if (!md.getReturnType().isVoid()) {
306       CompositeLocation returnLocComp = null;
307       Vector<AnnotationDescriptor> methodAnnotations = md.getModifiers().getAnnotations();
308       if (methodAnnotations != null) {
309         for (int i = 0; i < methodAnnotations.size(); i++) {
310           AnnotationDescriptor an = methodAnnotations.elementAt(i);
311           if (an.getMarker().equals(ssjava.RETURNLOC)) {
312             // developer explicitly defines method lattice
313             String returnLocDeclaration = an.getValue();
314             returnLocComp = parseLocationDeclaration(md, null, returnLocDeclaration);
315             md2ReturnLoc.put(md, returnLocComp);
316           }
317         }
318       }
319       if (returnLocComp == null) {
320         MethodLattice<String> methodDefaultLattice = ssjava.getMethodDefaultLattice(cd);
321         if (methodDefaultLattice.getReturnLoc() != null) {
322           returnLocComp = parseLocationDeclaration(md, null, methodDefaultLattice.getReturnLoc());
323           md2ReturnLoc.put(md, returnLocComp);
324         }
325       }
326
327       if (!md2ReturnLoc.containsKey(md)) {
328         throw new Error("Return location is not specified for the method " + md + " at "
329             + cd.getSourceFileName());
330       }
331
332       // check this location
333       MethodLattice<String> methodLattice = ssjava.getMethodLattice(md);
334       String thisLocId = methodLattice.getThisLoc();
335       if (thisLocId == null) {
336         throw new Error("Method '" + md + "' does not have the definition of 'this' location at "
337             + md.getClassDesc().getSourceFileName());
338       }
339       CompositeLocation thisLoc = new CompositeLocation(new Location(md, thisLocId));
340       paramList.add(0, thisLoc);
341
342       md2ReturnLocGen.put(md, new ReturnLocGenerator(md2ReturnLoc.get(md), paramList,
343           generateErrorMessage(cd, null)));
344     }
345
346     // third, check declarations inside of method
347
348     checkDeclarationInBlockNode(md, md.getParameterTable(), bn);
349
350   }
351
352   private void checkDeclarationInBlockNode(MethodDescriptor md, SymbolTable nametable, BlockNode bn) {
353     bn.getVarTable().setParent(nametable);
354     for (int i = 0; i < bn.size(); i++) {
355       BlockStatementNode bsn = bn.get(i);
356       checkDeclarationInBlockStatementNode(md, bn.getVarTable(), bsn);
357     }
358   }
359
360   private void checkDeclarationInBlockStatementNode(MethodDescriptor md, SymbolTable nametable,
361       BlockStatementNode bsn) {
362
363     switch (bsn.kind()) {
364     case Kind.SubBlockNode:
365       checkDeclarationInSubBlockNode(md, nametable, (SubBlockNode) bsn);
366       return;
367
368     case Kind.DeclarationNode:
369       checkDeclarationNode(md, nametable, (DeclarationNode) bsn);
370       break;
371
372     case Kind.LoopNode:
373       checkDeclarationInLoopNode(md, nametable, (LoopNode) bsn);
374       break;
375
376     case Kind.IfStatementNode:
377       checkDeclarationInIfStatementNode(md, nametable, (IfStatementNode) bsn);
378       return;
379
380     case Kind.SwitchStatementNode:
381       checkDeclarationInSwitchStatementNode(md, nametable, (SwitchStatementNode) bsn);
382       return;
383
384     case Kind.SynchronizedNode:
385       checkDeclarationInSynchronizedNode(md, nametable, (SynchronizedNode) bsn);
386       return;
387
388     }
389   }
390
391   private void checkDeclarationInSynchronizedNode(MethodDescriptor md, SymbolTable nametable,
392       SynchronizedNode sbn) {
393     checkDeclarationInBlockNode(md, nametable, sbn.getBlockNode());
394   }
395
396   private void checkDeclarationInSwitchStatementNode(MethodDescriptor md, SymbolTable nametable,
397       SwitchStatementNode ssn) {
398     BlockNode sbn = ssn.getSwitchBody();
399     for (int i = 0; i < sbn.size(); i++) {
400       SwitchBlockNode node = (SwitchBlockNode) sbn.get(i);
401       checkDeclarationInBlockNode(md, nametable, node.getSwitchBlockStatement());
402     }
403   }
404
405   private void checkDeclarationInIfStatementNode(MethodDescriptor md, SymbolTable nametable,
406       IfStatementNode isn) {
407     checkDeclarationInBlockNode(md, nametable, isn.getTrueBlock());
408     if (isn.getFalseBlock() != null)
409       checkDeclarationInBlockNode(md, nametable, isn.getFalseBlock());
410   }
411
412   private void checkDeclarationInLoopNode(MethodDescriptor md, SymbolTable nametable, LoopNode ln) {
413
414     if (ln.getType() == LoopNode.FORLOOP) {
415       // check for loop case
416       ClassDescriptor cd = md.getClassDesc();
417       BlockNode bn = ln.getInitializer();
418       for (int i = 0; i < bn.size(); i++) {
419         BlockStatementNode bsn = bn.get(i);
420         checkDeclarationInBlockStatementNode(md, nametable, bsn);
421       }
422     }
423
424     // check loop body
425     checkDeclarationInBlockNode(md, nametable, ln.getBody());
426   }
427
428   private void checkMethodBody(ClassDescriptor cd, MethodDescriptor md) {
429     BlockNode bn = state.getMethodBody(md);
430     checkLocationFromBlockNode(md, md.getParameterTable(), bn, null);
431   }
432
433   private String generateErrorMessage(ClassDescriptor cd, TreeNode tn) {
434     if (tn != null) {
435       return cd.getSourceFileName() + "::" + tn.getNumLine();
436     } else {
437       return cd.getSourceFileName();
438     }
439
440   }
441
442   private CompositeLocation checkLocationFromBlockNode(MethodDescriptor md, SymbolTable nametable,
443       BlockNode bn, CompositeLocation constraint) {
444
445     bn.getVarTable().setParent(nametable);
446     for (int i = 0; i < bn.size(); i++) {
447       BlockStatementNode bsn = bn.get(i);
448       checkLocationFromBlockStatementNode(md, bn.getVarTable(), bsn, constraint);
449     }
450     return new CompositeLocation();
451
452   }
453
454   private CompositeLocation checkLocationFromBlockStatementNode(MethodDescriptor md,
455       SymbolTable nametable, BlockStatementNode bsn, CompositeLocation constraint) {
456
457     CompositeLocation compLoc = null;
458     switch (bsn.kind()) {
459     case Kind.BlockExpressionNode:
460       compLoc =
461           checkLocationFromBlockExpressionNode(md, nametable, (BlockExpressionNode) bsn, constraint);
462       break;
463
464     case Kind.DeclarationNode:
465       compLoc = checkLocationFromDeclarationNode(md, nametable, (DeclarationNode) bsn, constraint);
466       break;
467
468     case Kind.IfStatementNode:
469       compLoc = checkLocationFromIfStatementNode(md, nametable, (IfStatementNode) bsn, constraint);
470       break;
471
472     case Kind.LoopNode:
473       compLoc = checkLocationFromLoopNode(md, nametable, (LoopNode) bsn, constraint);
474       break;
475
476     case Kind.ReturnNode:
477       compLoc = checkLocationFromReturnNode(md, nametable, (ReturnNode) bsn, constraint);
478       break;
479
480     case Kind.SubBlockNode:
481       compLoc = checkLocationFromSubBlockNode(md, nametable, (SubBlockNode) bsn, constraint);
482       break;
483
484     case Kind.ContinueBreakNode:
485       compLoc = new CompositeLocation();
486       break;
487
488     case Kind.SwitchStatementNode:
489       compLoc =
490           checkLocationFromSwitchStatementNode(md, nametable, (SwitchStatementNode) bsn, constraint);
491
492     }
493     return compLoc;
494   }
495
496   private CompositeLocation checkLocationFromSwitchStatementNode(MethodDescriptor md,
497       SymbolTable nametable, SwitchStatementNode ssn, CompositeLocation constraint) {
498
499     ClassDescriptor cd = md.getClassDesc();
500     CompositeLocation condLoc =
501         checkLocationFromExpressionNode(md, nametable, ssn.getCondition(), new CompositeLocation(),
502             constraint, false);
503     BlockNode sbn = ssn.getSwitchBody();
504
505     constraint = generateNewConstraint(constraint, condLoc);
506
507     for (int i = 0; i < sbn.size(); i++) {
508       checkLocationFromSwitchBlockNode(md, nametable, (SwitchBlockNode) sbn.get(i), constraint);
509     }
510     return new CompositeLocation();
511   }
512
513   private CompositeLocation checkLocationFromSwitchBlockNode(MethodDescriptor md,
514       SymbolTable nametable, SwitchBlockNode sbn, CompositeLocation constraint) {
515
516     CompositeLocation blockLoc =
517         checkLocationFromBlockNode(md, nametable, sbn.getSwitchBlockStatement(), constraint);
518
519     return blockLoc;
520
521   }
522
523   private CompositeLocation checkLocationFromReturnNode(MethodDescriptor md, SymbolTable nametable,
524       ReturnNode rn, CompositeLocation constraint) {
525
526     ExpressionNode returnExp = rn.getReturnExpression();
527
528     CompositeLocation returnValueLoc;
529     if (returnExp != null) {
530       returnValueLoc =
531           checkLocationFromExpressionNode(md, nametable, returnExp, new CompositeLocation(),
532               constraint, false);
533
534       // if this return statement is inside branch, return value has an implicit
535       // flow from conditional location
536       if (constraint != null) {
537         Set<CompositeLocation> inputGLB = new HashSet<CompositeLocation>();
538         inputGLB.add(returnValueLoc);
539         inputGLB.add(constraint);
540         returnValueLoc = CompositeLattice.calculateGLB(inputGLB);
541       }
542
543       // check if return value is equal or higher than RETRUNLOC of method
544       // declaration annotation
545       CompositeLocation declaredReturnLoc = md2ReturnLoc.get(md);
546
547       int compareResult =
548           CompositeLattice.compare(returnValueLoc, declaredReturnLoc,
549               generateErrorMessage(md.getClassDesc(), rn));
550
551       if (compareResult == ComparisonResult.LESS || compareResult == ComparisonResult.INCOMPARABLE) {
552         throw new Error(
553             "Return value location is not equal or higher than the declaraed return location at "
554                 + md.getClassDesc().getSourceFileName() + "::" + rn.getNumLine());
555       }
556     }
557
558     return new CompositeLocation();
559   }
560
561   private boolean hasOnlyLiteralValue(ExpressionNode en) {
562     if (en.kind() == Kind.LiteralNode) {
563       return true;
564     } else {
565       return false;
566     }
567   }
568
569   private CompositeLocation checkLocationFromLoopNode(MethodDescriptor md, SymbolTable nametable,
570       LoopNode ln, CompositeLocation constraint) {
571
572     ClassDescriptor cd = md.getClassDesc();
573     if (ln.getType() == LoopNode.WHILELOOP || ln.getType() == LoopNode.DOWHILELOOP) {
574
575       CompositeLocation condLoc =
576           checkLocationFromExpressionNode(md, nametable, ln.getCondition(),
577               new CompositeLocation(), constraint, false);
578       addLocationType(ln.getCondition().getType(), (condLoc));
579
580       constraint = generateNewConstraint(constraint, condLoc);
581       checkLocationFromBlockNode(md, nametable, ln.getBody(), constraint);
582
583       return new CompositeLocation();
584
585     } else {
586       // check 'for loop' case
587       BlockNode bn = ln.getInitializer();
588       bn.getVarTable().setParent(nametable);
589
590       // calculate glb location of condition and update statements
591       CompositeLocation condLoc =
592           checkLocationFromExpressionNode(md, bn.getVarTable(), ln.getCondition(),
593               new CompositeLocation(), constraint, false);
594       addLocationType(ln.getCondition().getType(), condLoc);
595
596       constraint = generateNewConstraint(constraint, condLoc);
597
598       checkLocationFromBlockNode(md, bn.getVarTable(), ln.getUpdate(), constraint);
599       checkLocationFromBlockNode(md, bn.getVarTable(), ln.getBody(), constraint);
600
601       return new CompositeLocation();
602
603     }
604
605   }
606
607   private CompositeLocation checkLocationFromSubBlockNode(MethodDescriptor md,
608       SymbolTable nametable, SubBlockNode sbn, CompositeLocation constraint) {
609     CompositeLocation compLoc =
610         checkLocationFromBlockNode(md, nametable, sbn.getBlockNode(), constraint);
611     return compLoc;
612   }
613
614   private CompositeLocation generateNewConstraint(CompositeLocation currentCon,
615       CompositeLocation newCon) {
616
617     if (currentCon == null) {
618       return newCon;
619     } else {
620       // compute GLB of current constraint and new constraint
621       Set<CompositeLocation> inputSet = new HashSet<CompositeLocation>();
622       inputSet.add(currentCon);
623       inputSet.add(newCon);
624       return CompositeLattice.calculateGLB(inputSet);
625     }
626
627   }
628
629   private CompositeLocation checkLocationFromIfStatementNode(MethodDescriptor md,
630       SymbolTable nametable, IfStatementNode isn, CompositeLocation constraint) {
631
632     CompositeLocation condLoc =
633         checkLocationFromExpressionNode(md, nametable, isn.getCondition(), new CompositeLocation(),
634             constraint, false);
635
636     addLocationType(isn.getCondition().getType(), condLoc);
637
638     constraint = generateNewConstraint(constraint, condLoc);
639     checkLocationFromBlockNode(md, nametable, isn.getTrueBlock(), constraint);
640
641     if (isn.getFalseBlock() != null) {
642       checkLocationFromBlockNode(md, nametable, isn.getFalseBlock(), constraint);
643     }
644
645     return new CompositeLocation();
646   }
647
648   private CompositeLocation checkLocationFromDeclarationNode(MethodDescriptor md,
649       SymbolTable nametable, DeclarationNode dn, CompositeLocation constraint) {
650
651     VarDescriptor vd = dn.getVarDescriptor();
652
653     CompositeLocation destLoc = d2loc.get(vd);
654
655     if (dn.getExpression() != null) {
656       CompositeLocation expressionLoc =
657           checkLocationFromExpressionNode(md, nametable, dn.getExpression(),
658               new CompositeLocation(), constraint, false);
659       // addTypeLocation(dn.getExpression().getType(), expressionLoc);
660
661       if (expressionLoc != null) {
662         // checking location order
663         if (!CompositeLattice.isGreaterThan(expressionLoc, destLoc,
664             generateErrorMessage(md.getClassDesc(), dn))) {
665           throw new Error("The value flow from " + expressionLoc + " to " + destLoc
666               + " does not respect location hierarchy on the assignment " + dn.printNode(0)
667               + " at " + md.getClassDesc().getSourceFileName() + "::" + dn.getNumLine());
668         }
669       }
670       return expressionLoc;
671
672     } else {
673
674       return new CompositeLocation();
675
676     }
677
678   }
679
680   private void checkDeclarationInSubBlockNode(MethodDescriptor md, SymbolTable nametable,
681       SubBlockNode sbn) {
682     checkDeclarationInBlockNode(md, nametable.getParent(), sbn.getBlockNode());
683   }
684
685   private CompositeLocation checkLocationFromBlockExpressionNode(MethodDescriptor md,
686       SymbolTable nametable, BlockExpressionNode ben, CompositeLocation constraint) {
687     CompositeLocation compLoc =
688         checkLocationFromExpressionNode(md, nametable, ben.getExpression(), null, constraint, false);
689     // addTypeLocation(ben.getExpression().getType(), compLoc);
690     return compLoc;
691   }
692
693   private CompositeLocation checkLocationFromExpressionNode(MethodDescriptor md,
694       SymbolTable nametable, ExpressionNode en, CompositeLocation loc,
695       CompositeLocation constraint, boolean isLHS) {
696
697     CompositeLocation compLoc = null;
698     switch (en.kind()) {
699
700     case Kind.AssignmentNode:
701       compLoc =
702           checkLocationFromAssignmentNode(md, nametable, (AssignmentNode) en, loc, constraint);
703       break;
704
705     case Kind.FieldAccessNode:
706       compLoc =
707           checkLocationFromFieldAccessNode(md, nametable, (FieldAccessNode) en, loc, constraint);
708       break;
709
710     case Kind.NameNode:
711       compLoc = checkLocationFromNameNode(md, nametable, (NameNode) en, loc, constraint);
712       break;
713
714     case Kind.OpNode:
715       compLoc = checkLocationFromOpNode(md, nametable, (OpNode) en, constraint);
716       break;
717
718     case Kind.CreateObjectNode:
719       compLoc = checkLocationFromCreateObjectNode(md, nametable, (CreateObjectNode) en);
720       break;
721
722     case Kind.ArrayAccessNode:
723       compLoc =
724           checkLocationFromArrayAccessNode(md, nametable, (ArrayAccessNode) en, constraint, isLHS);
725       break;
726
727     case Kind.LiteralNode:
728       compLoc = checkLocationFromLiteralNode(md, nametable, (LiteralNode) en, loc);
729       break;
730
731     case Kind.MethodInvokeNode:
732       compLoc =
733           checkLocationFromMethodInvokeNode(md, nametable, (MethodInvokeNode) en, loc, constraint);
734       break;
735
736     case Kind.TertiaryNode:
737       compLoc = checkLocationFromTertiaryNode(md, nametable, (TertiaryNode) en, constraint);
738       break;
739
740     case Kind.CastNode:
741       compLoc = checkLocationFromCastNode(md, nametable, (CastNode) en, constraint);
742       break;
743
744     // case Kind.InstanceOfNode:
745     // checkInstanceOfNode(md, nametable, (InstanceOfNode) en, td);
746     // return null;
747
748     // case Kind.ArrayInitializerNode:
749     // checkArrayInitializerNode(md, nametable, (ArrayInitializerNode) en,
750     // td);
751     // return null;
752
753     // case Kind.ClassTypeNode:
754     // checkClassTypeNode(md, nametable, (ClassTypeNode) en, td);
755     // return null;
756
757     // case Kind.OffsetNode:
758     // checkOffsetNode(md, nametable, (OffsetNode)en, td);
759     // return null;
760
761     default:
762       return null;
763
764     }
765     // addTypeLocation(en.getType(), compLoc);
766     return compLoc;
767
768   }
769
770   private CompositeLocation checkLocationFromCastNode(MethodDescriptor md, SymbolTable nametable,
771       CastNode cn, CompositeLocation constraint) {
772
773     ExpressionNode en = cn.getExpression();
774     return checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation(), constraint,
775         false);
776
777   }
778
779   private CompositeLocation checkLocationFromTertiaryNode(MethodDescriptor md,
780       SymbolTable nametable, TertiaryNode tn, CompositeLocation constraint) {
781     ClassDescriptor cd = md.getClassDesc();
782
783     CompositeLocation condLoc =
784         checkLocationFromExpressionNode(md, nametable, tn.getCond(), new CompositeLocation(),
785             constraint, false);
786     addLocationType(tn.getCond().getType(), condLoc);
787     CompositeLocation trueLoc =
788         checkLocationFromExpressionNode(md, nametable, tn.getTrueExpr(), new CompositeLocation(),
789             constraint, false);
790     addLocationType(tn.getTrueExpr().getType(), trueLoc);
791     CompositeLocation falseLoc =
792         checkLocationFromExpressionNode(md, nametable, tn.getFalseExpr(), new CompositeLocation(),
793             constraint, false);
794     addLocationType(tn.getFalseExpr().getType(), falseLoc);
795
796     // locations from true/false branches can be TOP when there are only literal
797     // values
798     // in this case, we don't need to check flow down rule!
799
800     // check if condLoc is higher than trueLoc & falseLoc
801     if (!trueLoc.get(0).isTop()
802         && !CompositeLattice.isGreaterThan(condLoc, trueLoc, generateErrorMessage(cd, tn))) {
803       throw new Error(
804           "The location of the condition expression is lower than the true expression at "
805               + cd.getSourceFileName() + ":" + tn.getCond().getNumLine());
806     }
807
808     if (!falseLoc.get(0).isTop()
809         && !CompositeLattice.isGreaterThan(condLoc, falseLoc,
810             generateErrorMessage(cd, tn.getCond()))) {
811       throw new Error(
812           "The location of the condition expression is lower than the true expression at "
813               + cd.getSourceFileName() + ":" + tn.getCond().getNumLine());
814     }
815
816     // then, return glb of trueLoc & falseLoc
817     Set<CompositeLocation> glbInputSet = new HashSet<CompositeLocation>();
818     glbInputSet.add(trueLoc);
819     glbInputSet.add(falseLoc);
820
821     return CompositeLattice.calculateGLB(glbInputSet);
822   }
823
824   private CompositeLocation checkLocationFromMethodInvokeNode(MethodDescriptor md,
825       SymbolTable nametable, MethodInvokeNode min, CompositeLocation loc,
826       CompositeLocation constraint) {
827
828     checkCalleeConstraints(md, nametable, min, constraint);
829
830     CompositeLocation baseLocation = null;
831     if (min.getExpression() != null) {
832       baseLocation =
833           checkLocationFromExpressionNode(md, nametable, min.getExpression(),
834               new CompositeLocation(), constraint, false);
835     } else {
836       String thisLocId = ssjava.getMethodLattice(md).getThisLoc();
837       baseLocation = new CompositeLocation(new Location(md, thisLocId));
838     }
839
840     if (!min.getMethod().getReturnType().isVoid()) {
841       // If method has a return value, compute the highest possible return
842       // location in the caller's perspective
843       CompositeLocation ceilingLoc =
844           computeCeilingLocationForCaller(md, nametable, min, baseLocation, constraint);
845       return ceilingLoc;
846     }
847
848     return new CompositeLocation();
849
850   }
851
852   private CompositeLocation computeCeilingLocationForCaller(MethodDescriptor md,
853       SymbolTable nametable, MethodInvokeNode min, CompositeLocation baseLocation,
854       CompositeLocation constraint) {
855     List<CompositeLocation> argList = new ArrayList<CompositeLocation>();
856
857     // by default, method has a THIS parameter
858     argList.add(baseLocation);
859
860     for (int i = 0; i < min.numArgs(); i++) {
861       ExpressionNode en = min.getArg(i);
862       CompositeLocation callerArg =
863           checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation(), constraint,
864               false);
865       argList.add(callerArg);
866     }
867
868     System.out.println("\n## computeReturnLocation=" + min.getMethod() + " argList=" + argList);
869     CompositeLocation compLoc = md2ReturnLocGen.get(min.getMethod()).computeReturnLocation(argList);
870     DeltaLocation delta = new DeltaLocation(compLoc, 1);
871     System.out.println("##computeReturnLocation=" + delta);
872
873     return delta;
874
875   }
876
877   private void checkCalleeConstraints(MethodDescriptor md, SymbolTable nametable,
878       MethodInvokeNode min, CompositeLocation constraint) {
879
880     if (min.numArgs() > 1) {
881       // caller needs to guarantee that it passes arguments in regarding to
882       // callee's hierarchy
883       for (int i = 0; i < min.numArgs(); i++) {
884         ExpressionNode en = min.getArg(i);
885         CompositeLocation callerArg1 =
886             checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation(), constraint,
887                 false);
888
889         VarDescriptor calleevd = (VarDescriptor) min.getMethod().getParameter(i);
890         CompositeLocation calleeLoc1 = d2loc.get(calleevd);
891
892         if (!callerArg1.get(0).isTop()) {
893           // here, check if ordering relations among caller's args respect
894           // ordering relations in-between callee's args
895           for (int currentIdx = 0; currentIdx < min.numArgs(); currentIdx++) {
896             if (currentIdx != i) { // skip itself
897               ExpressionNode argExp = min.getArg(currentIdx);
898
899               CompositeLocation callerArg2 =
900                   checkLocationFromExpressionNode(md, nametable, argExp, new CompositeLocation(),
901                       constraint, false);
902
903               VarDescriptor calleevd2 = (VarDescriptor) min.getMethod().getParameter(currentIdx);
904               CompositeLocation calleeLoc2 = d2loc.get(calleevd2);
905
906               int callerResult =
907                   CompositeLattice.compare(callerArg1, callerArg2,
908                       generateErrorMessage(md.getClassDesc(), min));
909               int calleeResult =
910                   CompositeLattice.compare(calleeLoc1, calleeLoc2,
911                       generateErrorMessage(md.getClassDesc(), min));
912
913               if (calleeResult == ComparisonResult.GREATER
914                   && callerResult != ComparisonResult.GREATER) {
915                 // If calleeLoc1 is higher than calleeLoc2
916                 // then, caller should have same ordering relation in-bet
917                 // callerLoc1 & callerLoc2
918
919                 throw new Error("Caller doesn't respect ordering relations among method arguments:"
920                     + md.getClassDesc().getSourceFileName() + ":" + min.getNumLine());
921               }
922
923             }
924           }
925         }
926
927       }
928
929     }
930
931   }
932
933   private CompositeLocation checkLocationFromArrayAccessNode(MethodDescriptor md,
934       SymbolTable nametable, ArrayAccessNode aan, CompositeLocation constraint, boolean isLHS) {
935
936     ClassDescriptor cd = md.getClassDesc();
937
938     CompositeLocation arrayLoc =
939         checkLocationFromExpressionNode(md, nametable, aan.getExpression(),
940             new CompositeLocation(), constraint, isLHS);
941     // addTypeLocation(aan.getExpression().getType(), arrayLoc);
942     CompositeLocation indexLoc =
943         checkLocationFromExpressionNode(md, nametable, aan.getIndex(), new CompositeLocation(),
944             constraint, isLHS);
945     // addTypeLocation(aan.getIndex().getType(), indexLoc);
946
947     if (isLHS) {
948       if (!CompositeLattice.isGreaterThan(indexLoc, arrayLoc, generateErrorMessage(cd, aan))) {
949         throw new Error("Array index value is not higher than array location at "
950             + generateErrorMessage(cd, aan));
951       }
952       return arrayLoc;
953     } else {
954       Set<CompositeLocation> inputGLB = new HashSet<CompositeLocation>();
955       inputGLB.add(arrayLoc);
956       inputGLB.add(indexLoc);
957       return CompositeLattice.calculateGLB(inputGLB);
958     }
959
960   }
961
962   private CompositeLocation checkLocationFromCreateObjectNode(MethodDescriptor md,
963       SymbolTable nametable, CreateObjectNode con) {
964
965     ClassDescriptor cd = md.getClassDesc();
966
967     CompositeLocation compLoc = new CompositeLocation();
968     compLoc.addLocation(Location.createTopLocation(md));
969     return compLoc;
970
971   }
972
973   private CompositeLocation checkLocationFromOpNode(MethodDescriptor md, SymbolTable nametable,
974       OpNode on, CompositeLocation constraint) {
975
976     ClassDescriptor cd = md.getClassDesc();
977     CompositeLocation leftLoc = new CompositeLocation();
978     leftLoc =
979         checkLocationFromExpressionNode(md, nametable, on.getLeft(), leftLoc, constraint, false);
980     // addTypeLocation(on.getLeft().getType(), leftLoc);
981
982     CompositeLocation rightLoc = new CompositeLocation();
983     if (on.getRight() != null) {
984       rightLoc =
985           checkLocationFromExpressionNode(md, nametable, on.getRight(), rightLoc, constraint, false);
986       // addTypeLocation(on.getRight().getType(), rightLoc);
987     }
988
989     System.out.println("\n# OP NODE=" + on.printNode(0));
990     System.out.println("# left loc=" + leftLoc + " from " + on.getLeft().getClass());
991     if (on.getRight() != null) {
992       System.out.println("# right loc=" + rightLoc + " from " + on.getRight().getClass());
993     }
994
995     Operation op = on.getOp();
996
997     switch (op.getOp()) {
998
999     case Operation.UNARYPLUS:
1000     case Operation.UNARYMINUS:
1001     case Operation.LOGIC_NOT:
1002       // single operand
1003       return leftLoc;
1004
1005     case Operation.LOGIC_OR:
1006     case Operation.LOGIC_AND:
1007     case Operation.COMP:
1008     case Operation.BIT_OR:
1009     case Operation.BIT_XOR:
1010     case Operation.BIT_AND:
1011     case Operation.ISAVAILABLE:
1012     case Operation.EQUAL:
1013     case Operation.NOTEQUAL:
1014     case Operation.LT:
1015     case Operation.GT:
1016     case Operation.LTE:
1017     case Operation.GTE:
1018     case Operation.ADD:
1019     case Operation.SUB:
1020     case Operation.MULT:
1021     case Operation.DIV:
1022     case Operation.MOD:
1023     case Operation.LEFTSHIFT:
1024     case Operation.RIGHTSHIFT:
1025     case Operation.URIGHTSHIFT:
1026
1027       Set<CompositeLocation> inputSet = new HashSet<CompositeLocation>();
1028       inputSet.add(leftLoc);
1029       inputSet.add(rightLoc);
1030       CompositeLocation glbCompLoc = CompositeLattice.calculateGLB(inputSet);
1031       return glbCompLoc;
1032
1033     default:
1034       throw new Error(op.toString());
1035     }
1036
1037   }
1038
1039   private CompositeLocation checkLocationFromLiteralNode(MethodDescriptor md,
1040       SymbolTable nametable, LiteralNode en, CompositeLocation loc) {
1041
1042     // literal value has the top location so that value can be flowed into any
1043     // location
1044     Location literalLoc = Location.createTopLocation(md);
1045     loc.addLocation(literalLoc);
1046     return loc;
1047
1048   }
1049
1050   private CompositeLocation checkLocationFromNameNode(MethodDescriptor md, SymbolTable nametable,
1051       NameNode nn, CompositeLocation loc, CompositeLocation constraint) {
1052
1053     NameDescriptor nd = nn.getName();
1054     if (nd.getBase() != null) {
1055       loc =
1056           checkLocationFromExpressionNode(md, nametable, nn.getExpression(), loc, constraint, false);
1057     } else {
1058       String varname = nd.toString();
1059       if (varname.equals("this")) {
1060         // 'this' itself!
1061         MethodLattice<String> methodLattice = ssjava.getMethodLattice(md);
1062         String thisLocId = methodLattice.getThisLoc();
1063         if (thisLocId == null) {
1064           throw new Error("The location for 'this' is not defined at "
1065               + md.getClassDesc().getSourceFileName() + "::" + nn.getNumLine());
1066         }
1067         Location locElement = new Location(md, thisLocId);
1068         loc.addLocation(locElement);
1069         return loc;
1070       }
1071
1072       Descriptor d = (Descriptor) nametable.get(varname);
1073
1074       // CompositeLocation localLoc = null;
1075       if (d instanceof VarDescriptor) {
1076         VarDescriptor vd = (VarDescriptor) d;
1077         // localLoc = d2loc.get(vd);
1078         // the type of var descriptor has a composite location!
1079         loc = ((CompositeLocation) vd.getType().getExtension()).clone();
1080       } else if (d instanceof FieldDescriptor) {
1081         // the type of field descriptor has a location!
1082         FieldDescriptor fd = (FieldDescriptor) d;
1083         if (fd.isStatic()) {
1084           if (fd.isFinal()) {
1085             // if it is 'static final', the location has TOP since no one can
1086             // change its value
1087             loc.addLocation(Location.createTopLocation(md));
1088             return loc;
1089           } else {
1090             // if 'static', the location has pre-assigned global loc
1091             MethodLattice<String> localLattice = ssjava.getMethodLattice(md);
1092             String globalLocId = localLattice.getGlobalLoc();
1093             if (globalLocId == null) {
1094               throw new Error("Global location element is not defined in the method " + md);
1095             }
1096             Location globalLoc = new Location(md, globalLocId);
1097
1098             loc.addLocation(globalLoc);
1099           }
1100         } else {
1101           // the location of field access starts from this, followed by field
1102           // location
1103           MethodLattice<String> localLattice = ssjava.getMethodLattice(md);
1104           Location thisLoc = new Location(md, localLattice.getThisLoc());
1105           loc.addLocation(thisLoc);
1106         }
1107
1108         Location fieldLoc = (Location) fd.getType().getExtension();
1109         loc.addLocation(fieldLoc);
1110       } else if (d == null) {
1111
1112         // check if the var is a static field of the class
1113         FieldDescriptor fd = nn.getField();
1114         ClassDescriptor cd = nn.getClassDesc();
1115
1116         if (fd != null && cd != null) {
1117
1118           if (fd.isStatic() && fd.isFinal()) {
1119             loc.addLocation(Location.createTopLocation(md));
1120             return loc;
1121           } else {
1122             MethodLattice<String> localLattice = ssjava.getMethodLattice(md);
1123             Location fieldLoc = new Location(md, localLattice.getThisLoc());
1124             loc.addLocation(fieldLoc);
1125           }
1126         }
1127
1128       }
1129     }
1130     return loc;
1131   }
1132
1133   private CompositeLocation checkLocationFromFieldAccessNode(MethodDescriptor md,
1134       SymbolTable nametable, FieldAccessNode fan, CompositeLocation loc,
1135       CompositeLocation constraint) {
1136
1137     ExpressionNode left = fan.getExpression();
1138     TypeDescriptor ltd = left.getType();
1139
1140     FieldDescriptor fd = fan.getField();
1141
1142     String varName = null;
1143     if (left.kind() == Kind.NameNode) {
1144       NameDescriptor nd = ((NameNode) left).getName();
1145       varName = nd.toString();
1146     }
1147
1148     if (ltd.isClassNameRef() || (varName != null && varName.equals("this"))) {
1149       // using a class name directly or access using this
1150       if (fd.isStatic() && fd.isFinal()) {
1151         loc.addLocation(Location.createTopLocation(md));
1152         return loc;
1153       }
1154     }
1155
1156     loc = checkLocationFromExpressionNode(md, nametable, left, loc, constraint, false);
1157     if (!left.getType().isPrimitive()) {
1158       Location fieldLoc = getFieldLocation(fd);
1159       loc.addLocation(fieldLoc);
1160     }
1161
1162     return loc;
1163   }
1164
1165   private Location getFieldLocation(FieldDescriptor fd) {
1166
1167     Location fieldLoc = (Location) fd.getType().getExtension();
1168
1169     // handle the case that method annotation checking skips checking field
1170     // declaration
1171     if (fieldLoc == null) {
1172       fieldLoc = checkFieldDeclaration(fd.getClassDescriptor(), fd);
1173     }
1174
1175     return fieldLoc;
1176
1177   }
1178
1179   private CompositeLocation checkLocationFromAssignmentNode(MethodDescriptor md,
1180       SymbolTable nametable, AssignmentNode an, CompositeLocation loc, CompositeLocation constraint) {
1181
1182     System.out.println("\n# ASSIGNMENTNODE=" + an.printNode(0));
1183
1184     ClassDescriptor cd = md.getClassDesc();
1185
1186     Set<CompositeLocation> inputGLBSet = new HashSet<CompositeLocation>();
1187
1188     boolean postinc = true;
1189     if (an.getOperation().getBaseOp() == null
1190         || (an.getOperation().getBaseOp().getOp() != Operation.POSTINC && an.getOperation()
1191             .getBaseOp().getOp() != Operation.POSTDEC))
1192       postinc = false;
1193
1194     // if LHS is array access node, need to check if array index is higher
1195     // than array itself
1196     CompositeLocation destLocation =
1197         checkLocationFromExpressionNode(md, nametable, an.getDest(), new CompositeLocation(),
1198             constraint, true);
1199
1200     CompositeLocation rhsLocation;
1201     CompositeLocation srcLocation;
1202
1203     if (!postinc) {
1204       rhsLocation =
1205           checkLocationFromExpressionNode(md, nametable, an.getSrc(), new CompositeLocation(),
1206               constraint, false);
1207
1208       System.out.println("dstLocation=" + destLocation);
1209       System.out.println("rhsLocation=" + rhsLocation);
1210       System.out.println("constraint=" + constraint);
1211
1212       if (constraint != null) {
1213         inputGLBSet.add(rhsLocation);
1214         inputGLBSet.add(constraint);
1215         srcLocation = CompositeLattice.calculateGLB(inputGLBSet);
1216       } else {
1217         srcLocation = rhsLocation;
1218       }
1219
1220       if (!CompositeLattice.isGreaterThan(srcLocation, destLocation, generateErrorMessage(cd, an))) {
1221         throw new Error("The value flow from " + srcLocation + " to " + destLocation
1222             + " does not respect location hierarchy on the assignment " + an.printNode(0) + " at "
1223             + cd.getSourceFileName() + "::" + an.getNumLine());
1224       }
1225
1226     } else {
1227       destLocation =
1228           rhsLocation =
1229               checkLocationFromExpressionNode(md, nametable, an.getDest(), new CompositeLocation(),
1230                   constraint, false);
1231
1232       if (constraint != null) {
1233         inputGLBSet.add(rhsLocation);
1234         inputGLBSet.add(constraint);
1235         srcLocation = CompositeLattice.calculateGLB(inputGLBSet);
1236       } else {
1237         srcLocation = rhsLocation;
1238       }
1239
1240       if (!CompositeLattice.isGreaterThan(srcLocation, destLocation, generateErrorMessage(cd, an))) {
1241         throw new Error("Location " + destLocation
1242             + " is not allowed to have the value flow that moves within the same location at "
1243             + cd.getSourceFileName() + "::" + an.getNumLine());
1244       }
1245
1246     }
1247
1248     return destLocation;
1249   }
1250
1251   private void assignLocationOfVarDescriptor(VarDescriptor vd, MethodDescriptor md,
1252       SymbolTable nametable, TreeNode n) {
1253
1254     ClassDescriptor cd = md.getClassDesc();
1255     Vector<AnnotationDescriptor> annotationVec = vd.getType().getAnnotationMarkers();
1256
1257     // currently enforce every variable to have corresponding location
1258     if (annotationVec.size() == 0) {
1259       throw new Error("Location is not assigned to variable " + vd.getSymbol() + " in the method "
1260           + md.getSymbol() + " of the class " + cd.getSymbol());
1261     }
1262
1263     if (annotationVec.size() > 1) { // variable can have at most one location
1264       throw new Error(vd.getSymbol() + " has more than one location.");
1265     }
1266
1267     AnnotationDescriptor ad = annotationVec.elementAt(0);
1268
1269     if (ad.getType() == AnnotationDescriptor.SINGLE_ANNOTATION) {
1270
1271       if (ad.getMarker().equals(SSJavaAnalysis.LOC)) {
1272         String locDec = ad.getValue(); // check if location is defined
1273
1274         if (locDec.startsWith(SSJavaAnalysis.DELTA)) {
1275           DeltaLocation deltaLoc = parseDeltaDeclaration(md, n, locDec);
1276           d2loc.put(vd, deltaLoc);
1277           addLocationType(vd.getType(), deltaLoc);
1278         } else {
1279           CompositeLocation compLoc = parseLocationDeclaration(md, n, locDec);
1280
1281           Location lastElement = compLoc.get(compLoc.getSize() - 1);
1282           if (ssjava.isSharedLocation(lastElement)) {
1283             ssjava.mapSharedLocation2Descriptor(lastElement, vd);
1284           }
1285
1286           d2loc.put(vd, compLoc);
1287           addLocationType(vd.getType(), compLoc);
1288         }
1289
1290       }
1291     }
1292
1293   }
1294
1295   private DeltaLocation parseDeltaDeclaration(MethodDescriptor md, TreeNode n, String locDec) {
1296
1297     int deltaCount = 0;
1298     int dIdx = locDec.indexOf(SSJavaAnalysis.DELTA);
1299     while (dIdx >= 0) {
1300       deltaCount++;
1301       int beginIdx = dIdx + 6;
1302       locDec = locDec.substring(beginIdx, locDec.length() - 1);
1303       dIdx = locDec.indexOf(SSJavaAnalysis.DELTA);
1304     }
1305
1306     CompositeLocation compLoc = parseLocationDeclaration(md, n, locDec);
1307     DeltaLocation deltaLoc = new DeltaLocation(compLoc, deltaCount);
1308
1309     return deltaLoc;
1310   }
1311
1312   private Location parseFieldLocDeclaraton(String decl, String msg) throws Exception {
1313
1314     int idx = decl.indexOf(".");
1315
1316     String className = decl.substring(0, idx);
1317     String fieldName = decl.substring(idx + 1);
1318
1319     className.replaceAll(" ", "");
1320     fieldName.replaceAll(" ", "");
1321
1322     Descriptor d = state.getClassSymbolTable().get(className);
1323
1324     if (d == null) {
1325       System.out.println("state.getClassSymbolTable()=" + state.getClassSymbolTable());
1326       throw new Error("The class in the location declaration '" + decl + "' does not exist at "
1327           + msg);
1328     }
1329
1330     assert (d instanceof ClassDescriptor);
1331     SSJavaLattice<String> lattice = ssjava.getClassLattice((ClassDescriptor) d);
1332     if (!lattice.containsKey(fieldName)) {
1333       throw new Error("The location " + fieldName + " is not defined in the field lattice of '"
1334           + className + "' at " + msg);
1335     }
1336
1337     return new Location(d, fieldName);
1338   }
1339
1340   private CompositeLocation parseLocationDeclaration(MethodDescriptor md, TreeNode n, String locDec) {
1341
1342     CompositeLocation compLoc = new CompositeLocation();
1343
1344     StringTokenizer tokenizer = new StringTokenizer(locDec, ",");
1345     List<String> locIdList = new ArrayList<String>();
1346     while (tokenizer.hasMoreTokens()) {
1347       String locId = tokenizer.nextToken();
1348       locIdList.add(locId);
1349     }
1350
1351     // at least,one location element needs to be here!
1352     assert (locIdList.size() > 0);
1353
1354     // assume that loc with idx 0 comes from the local lattice
1355     // loc with idx 1 comes from the field lattice
1356
1357     String localLocId = locIdList.get(0);
1358     SSJavaLattice<String> localLattice = CompositeLattice.getLatticeByDescriptor(md);
1359     Location localLoc = new Location(md, localLocId);
1360     if (localLattice == null || (!localLattice.containsKey(localLocId))) {
1361       System.out.println("locDec="+locDec);
1362       throw new Error("Location " + localLocId
1363           + " is not defined in the local variable lattice at "
1364           + md.getClassDesc().getSourceFileName() + "::" + (n != null ? n.getNumLine() : md) + ".");
1365     }
1366     compLoc.addLocation(localLoc);
1367
1368     for (int i = 1; i < locIdList.size(); i++) {
1369       String locName = locIdList.get(i);
1370       try {
1371         Location fieldLoc =
1372             parseFieldLocDeclaraton(locName, generateErrorMessage(md.getClassDesc(), n));
1373         compLoc.addLocation(fieldLoc);
1374       } catch (Exception e) {
1375         throw new Error("The location declaration '" + locName + "' is wrong  at "
1376             + generateErrorMessage(md.getClassDesc(), n));
1377       }
1378     }
1379
1380     return compLoc;
1381
1382   }
1383
1384   private void checkDeclarationNode(MethodDescriptor md, SymbolTable nametable, DeclarationNode dn) {
1385     VarDescriptor vd = dn.getVarDescriptor();
1386     assignLocationOfVarDescriptor(vd, md, nametable, dn);
1387   }
1388
1389   private void checkDeclarationInClass(ClassDescriptor cd) {
1390     // Check to see that fields are okay
1391     for (Iterator field_it = cd.getFields(); field_it.hasNext();) {
1392       FieldDescriptor fd = (FieldDescriptor) field_it.next();
1393
1394       if (!(fd.isFinal() && fd.isStatic())) {
1395         checkFieldDeclaration(cd, fd);
1396       } else {
1397         // for static final, assign top location by default
1398         Location loc = Location.createTopLocation(cd);
1399         addLocationType(fd.getType(), loc);
1400       }
1401     }
1402   }
1403
1404   private Location checkFieldDeclaration(ClassDescriptor cd, FieldDescriptor fd) {
1405
1406     Vector<AnnotationDescriptor> annotationVec = fd.getType().getAnnotationMarkers();
1407
1408     // currently enforce every field to have corresponding location
1409     if (annotationVec.size() == 0) {
1410       throw new Error("Location is not assigned to the field '" + fd.getSymbol()
1411           + "' of the class " + cd.getSymbol() + " at " + cd.getSourceFileName());
1412     }
1413
1414     if (annotationVec.size() > 1) {
1415       // variable can have at most one location
1416       throw new Error("Field " + fd.getSymbol() + " of class " + cd
1417           + " has more than one location.");
1418     }
1419
1420     AnnotationDescriptor ad = annotationVec.elementAt(0);
1421     Location loc = null;
1422
1423     if (ad.getType() == AnnotationDescriptor.SINGLE_ANNOTATION) {
1424       if (ad.getMarker().equals(SSJavaAnalysis.LOC)) {
1425         String locationID = ad.getValue();
1426         // check if location is defined
1427         SSJavaLattice<String> lattice = ssjava.getClassLattice(cd);
1428         if (lattice == null || (!lattice.containsKey(locationID))) {
1429           throw new Error("Location " + locationID
1430               + " is not defined in the field lattice of class " + cd.getSymbol() + " at"
1431               + cd.getSourceFileName() + ".");
1432         }
1433         loc = new Location(cd, locationID);
1434
1435         if (ssjava.isSharedLocation(loc)) {
1436           ssjava.mapSharedLocation2Descriptor(loc, fd);
1437         }
1438
1439         addLocationType(fd.getType(), loc);
1440
1441       }
1442     }
1443
1444     return loc;
1445   }
1446
1447   private void addLocationType(TypeDescriptor type, CompositeLocation loc) {
1448     if (type != null) {
1449       type.setExtension(loc);
1450     }
1451   }
1452
1453   private void addLocationType(TypeDescriptor type, Location loc) {
1454     if (type != null) {
1455       type.setExtension(loc);
1456     }
1457   }
1458
1459   static class CompositeLattice {
1460
1461     public static boolean isGreaterThan(CompositeLocation loc1, CompositeLocation loc2, String msg) {
1462
1463       System.out.println("\nisGreaterThan=" + loc1 + " " + loc2 + " msg=" + msg);
1464       int baseCompareResult = compareBaseLocationSet(loc1, loc2, true, msg);
1465       if (baseCompareResult == ComparisonResult.EQUAL) {
1466         if (compareDelta(loc1, loc2) == ComparisonResult.GREATER) {
1467           return true;
1468         } else {
1469           return false;
1470         }
1471       } else if (baseCompareResult == ComparisonResult.GREATER) {
1472         return true;
1473       } else {
1474         return false;
1475       }
1476
1477     }
1478
1479     public static int compare(CompositeLocation loc1, CompositeLocation loc2, String msg) {
1480
1481       System.out.println("compare=" + loc1 + " " + loc2);
1482       int baseCompareResult = compareBaseLocationSet(loc1, loc2, false, msg);
1483
1484       if (baseCompareResult == ComparisonResult.EQUAL) {
1485         return compareDelta(loc1, loc2);
1486       } else {
1487         return baseCompareResult;
1488       }
1489
1490     }
1491
1492     private static int compareDelta(CompositeLocation dLoc1, CompositeLocation dLoc2) {
1493
1494       int deltaCount1 = 0;
1495       int deltaCount2 = 0;
1496       if (dLoc1 instanceof DeltaLocation) {
1497         deltaCount1 = ((DeltaLocation) dLoc1).getNumDelta();
1498       }
1499
1500       if (dLoc2 instanceof DeltaLocation) {
1501         deltaCount2 = ((DeltaLocation) dLoc2).getNumDelta();
1502       }
1503       if (deltaCount1 < deltaCount2) {
1504         return ComparisonResult.GREATER;
1505       } else if (deltaCount1 == deltaCount2) {
1506         return ComparisonResult.EQUAL;
1507       } else {
1508         return ComparisonResult.LESS;
1509       }
1510
1511     }
1512
1513     private static int compareBaseLocationSet(CompositeLocation compLoc1,
1514         CompositeLocation compLoc2, boolean awareSharedLoc, String msg) {
1515
1516       // if compLoc1 is greater than compLoc2, return true
1517       // else return false;
1518
1519       // compare one by one in according to the order of the tuple
1520       int numOfTie = 0;
1521       for (int i = 0; i < compLoc1.getSize(); i++) {
1522         Location loc1 = compLoc1.get(i);
1523         if (i >= compLoc2.getSize()) {
1524           throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2
1525               + " because they are not comparable at " + msg);
1526         }
1527         Location loc2 = compLoc2.get(i);
1528
1529         Descriptor d1 = loc1.getDescriptor();
1530         Descriptor d2 = loc2.getDescriptor();
1531
1532         Descriptor descriptor;
1533
1534         if (d1 instanceof ClassDescriptor && d2 instanceof ClassDescriptor) {
1535
1536           if (d1.equals(d2)) {
1537             descriptor = d1;
1538           } else {
1539             // identifying which one is parent class
1540             Set<Descriptor> d1SubClassesSet = ssjava.tu.getSubClasses((ClassDescriptor) d1);
1541             Set<Descriptor> d2SubClassesSet = ssjava.tu.getSubClasses((ClassDescriptor) d2);
1542
1543             if (d1 == null && d2 == null) {
1544               throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2
1545                   + " because they are not comparable at " + msg);
1546             } else if (d1SubClassesSet != null && d1SubClassesSet.contains(d2)) {
1547               descriptor = d1;
1548             } else if (d2SubClassesSet != null && d2SubClassesSet.contains(d1)) {
1549               descriptor = d2;
1550             } else {
1551               throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2
1552                   + " because they are not comparable at " + msg);
1553             }
1554           }
1555
1556         } else if (d1 instanceof MethodDescriptor && d2 instanceof MethodDescriptor) {
1557
1558           if (d1.equals(d2)) {
1559             descriptor = d1;
1560           } else {
1561
1562             // identifying which one is parent class
1563             MethodDescriptor md1 = (MethodDescriptor) d1;
1564             MethodDescriptor md2 = (MethodDescriptor) d2;
1565
1566             if (!md1.matches(md2)) {
1567               throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2
1568                   + " because they are not comparable at " + msg);
1569             }
1570
1571             Set<Descriptor> d1SubClassesSet =
1572                 ssjava.tu.getSubClasses(((MethodDescriptor) d1).getClassDesc());
1573             Set<Descriptor> d2SubClassesSet =
1574                 ssjava.tu.getSubClasses(((MethodDescriptor) d2).getClassDesc());
1575
1576             if (d1 == null && d2 == null) {
1577               throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2
1578                   + " because they are not comparable at " + msg);
1579             } else if (d1 != null && d1SubClassesSet.contains(d2)) {
1580               descriptor = d1;
1581             } else if (d2 != null && d2SubClassesSet.contains(d1)) {
1582               descriptor = d2;
1583             } else {
1584               throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2
1585                   + " because they are not comparable at " + msg);
1586             }
1587           }
1588
1589         } else {
1590           throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2
1591               + " because they are not comparable at " + msg);
1592         }
1593
1594         // SSJavaLattice<String> lattice1 = getLatticeByDescriptor(d1);
1595         // SSJavaLattice<String> lattice2 = getLatticeByDescriptor(d2);
1596
1597         SSJavaLattice<String> lattice = getLatticeByDescriptor(descriptor);
1598
1599         // check if the spin location is appeared only at the end of the
1600         // composite location
1601         if (lattice.getSpinLocSet().contains(loc1.getLocIdentifier())) {
1602           if (i != (compLoc1.getSize() - 1)) {
1603             throw new Error("The shared location " + loc1.getLocIdentifier()
1604                 + " cannot be appeared in the middle of composite location at" + msg);
1605           }
1606         }
1607
1608         if (lattice.getSpinLocSet().contains(loc2.getLocIdentifier())) {
1609           if (i != (compLoc2.getSize() - 1)) {
1610             throw new Error("The spin location " + loc2.getLocIdentifier()
1611                 + " cannot be appeared in the middle of composite location at " + msg);
1612           }
1613         }
1614
1615         // if (!lattice1.equals(lattice2)) {
1616         // throw new Error("Failed to compare two locations of " + compLoc1 +
1617         // " and " + compLoc2
1618         // + " because they are not comparable at " + msg);
1619         // }
1620
1621         if (loc1.getLocIdentifier().equals(loc2.getLocIdentifier())) {
1622           numOfTie++;
1623           // check if the current location is the spinning location
1624           // note that the spinning location only can be appeared in the last
1625           // part of the composite location
1626           if (awareSharedLoc && numOfTie == compLoc1.getSize()
1627               && lattice.getSpinLocSet().contains(loc1.getLocIdentifier())) {
1628             return ComparisonResult.GREATER;
1629           }
1630           continue;
1631         } else if (lattice.isGreaterThan(loc1.getLocIdentifier(), loc2.getLocIdentifier())) {
1632           return ComparisonResult.GREATER;
1633         } else {
1634           return ComparisonResult.LESS;
1635         }
1636
1637       }
1638
1639       if (numOfTie == compLoc1.getSize()) {
1640
1641         if (numOfTie != compLoc2.getSize()) {
1642           throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2
1643               + " because they are not comparable at " + msg);
1644         }
1645
1646         return ComparisonResult.EQUAL;
1647       }
1648
1649       return ComparisonResult.LESS;
1650
1651     }
1652
1653     public static CompositeLocation calculateGLB(Set<CompositeLocation> inputSet) {
1654
1655       // System.out.println("Calculating GLB=" + inputSet);
1656       CompositeLocation glbCompLoc = new CompositeLocation();
1657
1658       // calculate GLB of the first(priority) element
1659       Set<String> priorityLocIdentifierSet = new HashSet<String>();
1660       Descriptor priorityDescriptor = null;
1661
1662       Hashtable<String, Set<CompositeLocation>> locId2CompLocSet =
1663           new Hashtable<String, Set<CompositeLocation>>();
1664       // mapping from the priority loc ID to its full representation by the
1665       // composite location
1666
1667       int maxTupleSize = 0;
1668       CompositeLocation maxCompLoc = null;
1669
1670       for (Iterator iterator = inputSet.iterator(); iterator.hasNext();) {
1671         CompositeLocation compLoc = (CompositeLocation) iterator.next();
1672         if (compLoc.getSize() > maxTupleSize) {
1673           maxTupleSize = compLoc.getSize();
1674           maxCompLoc = compLoc;
1675         }
1676         Location priorityLoc = compLoc.get(0);
1677         String priorityLocId = priorityLoc.getLocIdentifier();
1678         priorityLocIdentifierSet.add(priorityLocId);
1679
1680         if (locId2CompLocSet.containsKey(priorityLocId)) {
1681           locId2CompLocSet.get(priorityLocId).add(compLoc);
1682         } else {
1683           Set<CompositeLocation> newSet = new HashSet<CompositeLocation>();
1684           newSet.add(compLoc);
1685           locId2CompLocSet.put(priorityLocId, newSet);
1686         }
1687
1688         // check if priority location are coming from the same lattice
1689         if (priorityDescriptor == null) {
1690           priorityDescriptor = priorityLoc.getDescriptor();
1691         } else if (!priorityDescriptor.equals(priorityLoc.getDescriptor())) {
1692           throw new Error("Failed to calculate GLB of " + inputSet
1693               + " because they are from different lattices.");
1694         }
1695       }
1696
1697       SSJavaLattice<String> locOrder = getLatticeByDescriptor(priorityDescriptor);
1698       String glbOfPriorityLoc = locOrder.getGLB(priorityLocIdentifierSet);
1699
1700       glbCompLoc.addLocation(new Location(priorityDescriptor, glbOfPriorityLoc));
1701       Set<CompositeLocation> compSet = locId2CompLocSet.get(glbOfPriorityLoc);
1702
1703       if (compSet == null) {
1704         // when GLB(x1,x2)!=x1 and !=x2 : GLB case 4
1705         // mean that the result is already lower than <x1,y1> and <x2,y2>
1706         // assign TOP to the rest of the location elements
1707
1708         // in this case, do not take care about delta
1709         // CompositeLocation inputComp = inputSet.iterator().next();
1710         for (int i = 1; i < maxTupleSize; i++) {
1711           glbCompLoc.addLocation(Location.createTopLocation(maxCompLoc.get(i).getDescriptor()));
1712         }
1713       } else {
1714
1715         // here find out composite location that has a maximum length tuple
1716         // if we have three input set: [A], [A,B], [A,B,C]
1717         // maximum length tuple will be [A,B,C]
1718         int max = 0;
1719         CompositeLocation maxFromCompSet = null;
1720         for (Iterator iterator = compSet.iterator(); iterator.hasNext();) {
1721           CompositeLocation c = (CompositeLocation) iterator.next();
1722           if (c.getSize() > max) {
1723             max = c.getSize();
1724             maxFromCompSet = c;
1725           }
1726         }
1727
1728         if (compSet.size() == 1) {
1729
1730           // if GLB(x1,x2)==x1 or x2 : GLB case 2,3
1731           CompositeLocation comp = compSet.iterator().next();
1732           for (int i = 1; i < comp.getSize(); i++) {
1733             glbCompLoc.addLocation(comp.get(i));
1734           }
1735
1736           // if input location corresponding to glb is a delta, need to apply
1737           // delta to glb result
1738           if (comp instanceof DeltaLocation) {
1739             glbCompLoc = new DeltaLocation(glbCompLoc, 1);
1740           }
1741
1742         } else {
1743           // when GLB(x1,x2)==x1 and x2 : GLB case 1
1744           // if more than one location shares the same priority GLB
1745           // need to calculate the rest of GLB loc
1746
1747           // int compositeLocSize = compSet.iterator().next().getSize();
1748           int compositeLocSize = maxFromCompSet.getSize();
1749
1750           Set<String> glbInputSet = new HashSet<String>();
1751           Descriptor currentD = null;
1752           for (int i = 1; i < compositeLocSize; i++) {
1753             for (Iterator iterator = compSet.iterator(); iterator.hasNext();) {
1754               CompositeLocation compositeLocation = (CompositeLocation) iterator.next();
1755               if (compositeLocation.getSize() > i) {
1756                 Location currentLoc = compositeLocation.get(i);
1757                 currentD = currentLoc.getDescriptor();
1758                 // making set of the current location sharing the same idx
1759                 glbInputSet.add(currentLoc.getLocIdentifier());
1760               }
1761             }
1762             // calculate glb for the current lattice
1763
1764             SSJavaLattice<String> currentLattice = getLatticeByDescriptor(currentD);
1765             String currentGLBLocId = currentLattice.getGLB(glbInputSet);
1766             glbCompLoc.addLocation(new Location(currentD, currentGLBLocId));
1767           }
1768
1769           // if input location corresponding to glb is a delta, need to apply
1770           // delta to glb result
1771
1772           for (Iterator iterator = compSet.iterator(); iterator.hasNext();) {
1773             CompositeLocation compLoc = (CompositeLocation) iterator.next();
1774             if (compLoc instanceof DeltaLocation) {
1775               if (glbCompLoc.equals(compLoc)) {
1776                 glbCompLoc = new DeltaLocation(glbCompLoc, 1);
1777                 break;
1778               }
1779             }
1780           }
1781
1782         }
1783       }
1784
1785       return glbCompLoc;
1786
1787     }
1788
1789     static SSJavaLattice<String> getLatticeByDescriptor(Descriptor d) {
1790
1791       SSJavaLattice<String> lattice = null;
1792
1793       if (d instanceof ClassDescriptor) {
1794         lattice = ssjava.getCd2lattice().get(d);
1795       } else if (d instanceof MethodDescriptor) {
1796         if (ssjava.getMd2lattice().containsKey(d)) {
1797           lattice = ssjava.getMd2lattice().get(d);
1798         } else {
1799           // use default lattice for the method
1800           lattice = ssjava.getCd2methodDefault().get(((MethodDescriptor) d).getClassDesc());
1801         }
1802       }
1803
1804       return lattice;
1805     }
1806
1807   }
1808
1809   class ComparisonResult {
1810
1811     public static final int GREATER = 0;
1812     public static final int EQUAL = 1;
1813     public static final int LESS = 2;
1814     public static final int INCOMPARABLE = 3;
1815     int result;
1816
1817   }
1818
1819 }
1820
1821 class ReturnLocGenerator {
1822
1823   public static final int PARAMISHIGHER = 0;
1824   public static final int PARAMISSAME = 1;
1825   public static final int IGNORE = 2;
1826
1827   Hashtable<Integer, Integer> paramIdx2paramType;
1828
1829   public ReturnLocGenerator(CompositeLocation returnLoc, List<CompositeLocation> params, String msg) {
1830     // creating mappings
1831     paramIdx2paramType = new Hashtable<Integer, Integer>();
1832     for (int i = 0; i < params.size(); i++) {
1833       CompositeLocation param = params.get(i);
1834       int compareResult = CompositeLattice.compare(param, returnLoc, msg);
1835
1836       int type;
1837       if (compareResult == ComparisonResult.GREATER) {
1838         type = 0;
1839       } else if (compareResult == ComparisonResult.EQUAL) {
1840         type = 1;
1841       } else {
1842         type = 2;
1843       }
1844       paramIdx2paramType.put(new Integer(i), new Integer(type));
1845     }
1846
1847   }
1848
1849   public CompositeLocation computeReturnLocation(List<CompositeLocation> args) {
1850
1851     // compute the highest possible location in caller's side
1852     assert paramIdx2paramType.keySet().size() == args.size();
1853
1854     Set<CompositeLocation> inputGLB = new HashSet<CompositeLocation>();
1855     for (int i = 0; i < args.size(); i++) {
1856       int type = (paramIdx2paramType.get(new Integer(i))).intValue();
1857       CompositeLocation argLoc = args.get(i);
1858       if (type == PARAMISHIGHER) {
1859         // return loc is lower than param
1860         DeltaLocation delta = new DeltaLocation(argLoc, 1);
1861         inputGLB.add(delta);
1862       } else if (type == PARAMISSAME) {
1863         // return loc is equal or lower than param
1864         inputGLB.add(argLoc);
1865       }
1866     }
1867
1868     // compute GLB of arguments subset that are same or higher than return
1869     // location
1870     CompositeLocation glb = CompositeLattice.calculateGLB(inputGLB);
1871     return glb;
1872   }
1873 }