implemented PCLOC annotation.
[IRC.git] / Robust / src / IR / ClassDescriptor.java
1 package IR;
2 import java.util.*;
3 import IR.Tree.*;
4 import Util.Lattice;
5
6 public class ClassDescriptor extends Descriptor {
7   private static int UIDCount=1; // start from 1 instead of 0 for multicore gc
8   private final int classid;
9   String superclass;
10   ClassDescriptor superdesc;
11   boolean hasFlags=false;
12   String packagename;
13   String classname;
14
15   Modifiers modifiers;
16
17   SymbolTable fields;
18   Vector fieldvec;
19   SymbolTable flags;
20   SymbolTable methods;
21   boolean inline=false;
22
23   ChainHashMap mandatoryImports;
24   ChainHashMap multiImports;
25
26   int numstaticblocks = 0;
27   int numstaticfields = 0;
28
29   // for interfaces
30   Vector<String> superinterfaces;
31   SymbolTable superIFdesc;
32   private int interfaceid;
33
34   // for inner classes
35   boolean isInnerClass=false;
36
37   // inner classes/enum can have these
38   String surroundingclass=null;
39   //adding another variable to indicate depth of this inner class 
40   int innerDepth = 0;
41   ClassDescriptor surroundingdesc=null;
42   SymbolTable surroundingNameTable = null;
43   MethodDescriptor surroundingBlock=null;
44   boolean inStaticContext=false;
45
46   SymbolTable innerdescs;
47
48   // for enum type
49   boolean isEnum = false;
50   SymbolTable enumdescs;
51   HashMap<String, Integer> enumConstantTbl;
52   int enumconstantid = 0;
53
54   String sourceFileName;
55
56   public ClassDescriptor(String classname, boolean isInterface) {
57     this("", classname, isInterface);
58   }
59
60   public ClassDescriptor(String packagename, String classname, boolean isInterface) {
61     //make the name canonical by class file path (i.e. package)
62     super(packagename!=null?packagename+"."+classname:classname);
63     this.classname=classname;
64     superclass=null;
65     flags=new SymbolTable();
66     fields=new SymbolTable();
67     fieldvec=new Vector();
68     methods=new SymbolTable();
69     if(isInterface) {
70       this.classid = -2;
71       this.interfaceid = -1;
72     } else {
73       classid=UIDCount++;
74     }
75     this.packagename=packagename;
76     superinterfaces = new Vector<String>();
77     superIFdesc = new SymbolTable();
78     this.innerdescs = new SymbolTable();
79     this.enumdescs = new SymbolTable();
80   }
81
82   public int getId() {
83     if(this.isInterface()) {
84       return this.interfaceid;
85     }
86     return classid;
87   }
88
89   public Iterator getMethods() {
90     return methods.getDescriptorsIterator();
91   }
92
93   public Iterator getFields() {
94     return fields.getDescriptorsIterator();
95   }
96
97   public Iterator getFlags() {
98     return flags.getDescriptorsIterator();
99   }
100
101   public Iterator getSuperInterfaces() {
102     return this.superIFdesc.getDescriptorsIterator();
103   }
104
105   public SymbolTable getFieldTable() {
106     return fields;
107   }
108
109   public Vector getFieldVec() {
110     return fieldvec;
111   }
112
113   public String getClassName() {
114     return classname;
115   }
116
117   public String getPackage() {
118     return packagename;
119   }
120
121   public SymbolTable getFlagTable() {
122     return flags;
123   }
124
125   public SymbolTable getMethodTable() {
126     return methods;
127   }
128
129   public SymbolTable getSuperInterfaceTable() {
130     return this.superIFdesc;
131   }
132
133   public String getSafeDescriptor() {
134     return "L"+safename.replace(".","___________").replace("$","___DOLLAR___");
135   }
136
137   public String getSafeSymbol() {
138     return safename.replace(".","___________").replace("$","___DOLLAR___");
139   }
140
141   public String printTree(State state) {
142     int indent;
143     String st=modifiers.toString()+"class "+getSymbol();
144     if (superclass!=null)
145       st+="extends "+superclass.toString();
146     if(this.superinterfaces != null) {
147       st += "implements ";
148       boolean needcomma = false;
149       for(int i = 0; i < this.superinterfaces.size(); i++) {
150         if(needcomma) {
151           st += ", ";
152         }
153         st += this.superinterfaces.elementAt(i);
154         needcomma = true;
155       }
156     }
157     st+=" {\n";
158     indent=TreeNode.INDENT;
159     boolean printcr=false;
160
161     for(Iterator it=getFlags(); it.hasNext(); ) {
162       FlagDescriptor fd=(FlagDescriptor)it.next();
163       st+=TreeNode.printSpace(indent)+fd.toString()+"\n";
164       printcr=true;
165     }
166     if (printcr)
167       st+="\n";
168
169     printcr=false;
170
171     for(Iterator it=getFields(); it.hasNext(); ) {
172       FieldDescriptor fd=(FieldDescriptor)it.next();
173       st+=TreeNode.printSpace(indent)+fd.toString()+"\n";
174       printcr=true;
175     }
176     if (printcr)
177       st+="\n";
178
179     for(Iterator it=this.getInnerClasses(); it.hasNext(); ) {
180       ClassDescriptor icd=(ClassDescriptor)it.next();
181       st+=icd.printTree(state)+"\n";
182       printcr=true;
183     }
184     if (printcr)
185       st+="\n";
186
187     for(Iterator it=this.getEnum(); it.hasNext(); ) {
188       ClassDescriptor icd = (ClassDescriptor)it.next();
189       st += icd.getModifier().toString() + " enum " + icd.getSymbol() + " {\n  ";
190       Set keys = icd.getEnumConstantTbl().keySet();
191       String[] econstants = new String[keys.size()];
192       Iterator it_keys = keys.iterator();
193       while(it_keys.hasNext()) {
194         String key = (String)it_keys.next();
195         econstants[icd.getEnumConstant(key)] = key;
196       }
197       for(int i = 0; i < econstants.length; i++) {
198         st += econstants[i];
199         if(i < econstants.length-1) {
200           st += ", ";
201         }
202       }
203       st+="\n}\n";
204       printcr=true;
205     }
206     if (printcr)
207       st+="\n";
208
209     for(Iterator it=getMethods(); it.hasNext(); ) {
210       MethodDescriptor md=(MethodDescriptor)it.next();
211       st+=TreeNode.printSpace(indent)+md.toString()+" ";
212       BlockNode bn=state.getMethodBody(md);
213       st+=bn.printNode(indent)+"\n\n";
214     }
215     st+="}\n";
216     return st;
217   }
218
219   public MethodDescriptor getCalledMethod(MethodDescriptor md) {
220     ClassDescriptor cn=this;
221     while(true) {
222       if (cn==null) {
223         // TODO: the original code returned "null" if no super class
224         // ever defines the method.  Is there a situation where this is
225         // fine and the client should take other actions?  If not, we should
226         // change this warning to an error.
227         System.out.println("ClassDescriptor.java: WARNING "+md+
228                            " did not resolve to an actual method.");
229         return null;
230       }
231       Set possiblematches=cn.getMethodTable().getSetFromSameScope(md.getSymbol());
232       for(Iterator matchit=possiblematches.iterator(); matchit.hasNext(); ) {
233         MethodDescriptor matchmd=(MethodDescriptor)matchit.next();
234
235         if (md.matches(matchmd)) {
236           return matchmd;
237         }
238       }
239
240       //Not found...walk one level up
241       cn=cn.getSuperDesc();
242     }
243   }
244
245   public void addFlag(FlagDescriptor fd) {
246     if (flags.contains(fd.getSymbol()))
247       throw new Error(fd.getSymbol()+" already defined");
248     hasFlags=true;
249     flags.add(fd);
250   }
251
252   public boolean hasFlags() {
253     return hasFlags||getSuperDesc()!=null&&getSuperDesc().hasFlags();
254   }
255
256   public void addField(FieldDescriptor fd) {
257     if (fields.contains(fd.getSymbol()))
258       throw new Error(fd.getSymbol()+" already defined");
259     fields.add(fd);
260     fieldvec.add(fd);
261     if(fd.isStatic()) {
262       this.incStaticFields();
263     }
264     fd.setClassDescriptor(this);
265   }
266
267   public void addMethod(MethodDescriptor md) {
268     methods.add(md);
269   }
270
271   public void setModifiers(Modifiers modifiers) {
272     this.modifiers=modifiers;
273   }
274
275   public void setInline() {
276     this.inline=true;
277   }
278
279   public boolean getInline() {
280     return inline;
281   }
282
283   public void setSuper(String superclass) {
284     this.superclass=superclass;
285   }
286
287   public ClassDescriptor getSuperDesc() {
288     return superdesc;
289   }
290
291   public void setSuperDesc(ClassDescriptor scd) {
292     this.superdesc=scd;
293   }
294
295   public String getSuper() {
296     return superclass;
297   }
298
299   public void addSuperInterface(String superif) {
300     this.superinterfaces.addElement(superif);
301   }
302
303   public Vector<String> getSuperInterface() {
304     return this.superinterfaces;
305   }
306
307   public void addSuperInterfaces(ClassDescriptor sif) {
308     this.superIFdesc.add(sif);
309   }
310
311   public void incStaticBlocks() {
312     this.numstaticblocks++;
313   }
314
315   public int getNumStaticBlocks() {
316     return this.numstaticblocks;
317   }
318
319   public void incStaticFields() {
320     this.numstaticfields++;
321   }
322
323   public int getNumStaticFields() {
324     return this.numstaticfields;
325   }
326
327   public boolean isAbstract() {
328     return this.modifiers.isAbstract();
329   }
330
331   public boolean isInterface() {
332     return (this.classid == -2);
333   }
334
335   public void setInterfaceId(int id) {
336     this.interfaceid = id;
337   }
338
339   public boolean isStatic() {
340     return this.modifiers.isStatic();
341   }
342
343   public void setAsInnerClass() {
344     this.isInnerClass = true;
345   }
346   //Will have to call this whenever we are adding the this$ member, ideally should have used a single entrance to add the field. so that entrance could be used to set this flag.
347   public void setInnerDepth( int theDepth ) {
348         innerDepth = theDepth;
349   }
350
351   public int getInnerDepth() {
352         return innerDepth;
353   }
354
355   public boolean isInnerClass() {
356     return this.isInnerClass;
357   }
358
359   public void setSurroundingClass(String sclass) {
360     this.surroundingclass=sclass;
361   }
362
363   public String getSurrounding() {
364     return this.surroundingclass;
365   }
366
367   public ClassDescriptor getSurroundingDesc() {
368     return this.surroundingdesc;
369   }
370
371   public void setSurrounding(ClassDescriptor scd) {
372     this.surroundingdesc=scd;
373   }
374
375   public void addInnerClass(ClassDescriptor icd) {
376     this.innerdescs.add(icd);
377   }
378
379   public Iterator getInnerClasses() {
380     return this.innerdescs.getDescriptorsIterator();
381   }
382
383   public SymbolTable getInnerClassTable() {
384     return this.innerdescs;
385   }
386
387   public void setAsEnum() {
388     this.isEnum = true;
389   }
390
391   public boolean isEnum() {
392     return this.isEnum;
393   }
394
395   public void addEnum(ClassDescriptor icd) {
396     this.enumdescs.add(icd);
397   }
398
399   public Iterator getEnum() {
400     return this.enumdescs.getDescriptorsIterator();
401   }
402
403   public SymbolTable getEnumTable() {
404     return this.enumdescs;
405   }
406
407   public void addEnumConstant(String econstant) {
408     if(this.enumConstantTbl == null) {
409       this.enumConstantTbl = new HashMap<String, Integer>();
410     }
411     if(this.enumConstantTbl.containsKey(econstant)) {
412       return;
413     } else {
414       this.enumConstantTbl.put(econstant, this.enumconstantid++);
415     }
416     return;
417   }
418
419   public int getEnumConstant(String econstant) {
420     if(this.enumConstantTbl.containsKey(econstant)) {
421       return this.enumConstantTbl.get(econstant).intValue();
422     } else {
423       return -1;
424     }
425   }
426
427   public HashMap<String, Integer> getEnumConstantTbl() {
428     return this.enumConstantTbl;
429   }
430
431   public Modifiers getModifier() {
432     return this.modifiers;
433   }
434
435   public void setSourceFileName(String sourceFileName) {
436     this.sourceFileName=sourceFileName;
437   }
438
439   public void setImports(ChainHashMap singleImports, ChainHashMap multiImports) {
440     this.mandatoryImports = singleImports;
441     this.multiImports = multiImports;
442   }
443
444   public String getSourceFileName() {
445     return this.sourceFileName;
446   }
447
448   public ChainHashMap getSingleImportMappings() {
449     return this.mandatoryImports;
450   }
451   
452   public ChainHashMap getMultiImportMappings() {
453     return this.multiImports;
454   }
455
456   //Returns the full name/path of another class referenced from this class via imports.
457   public String getCanonicalImportMapName(String otherClassname) {
458     if(mandatoryImports.containsKey(otherClassname)) {
459       return (String) mandatoryImports.get(otherClassname);
460     } else if(multiImports.containsKey(otherClassname)) {
461       //Test for error
462       Object o = multiImports.get(otherClassname);
463       if(o instanceof Error) {
464         throw new Error("Class " + otherClassname + " is ambiguous. Cause: more than 1 package import contain the same class.");
465       } else {
466         //At this point, if we found a unique class
467         //we can treat it as a single, mandatory import.
468         mandatoryImports.put(otherClassname, o);
469         return (String) o;
470       }
471     } else {
472       return otherClassname;
473     }
474   }
475   
476   public void setSurroundingNameTable(SymbolTable nametable) {
477     this.surroundingNameTable = nametable;
478   }
479   
480   public SymbolTable getSurroundingNameTable() {
481     return this.surroundingNameTable;
482   }
483   
484   public void setSurroundingBlock(MethodDescriptor md) {
485     this.surroundingBlock = md;
486   }
487   
488   public MethodDescriptor getSurroundingBlock() {
489     return this.surroundingBlock;
490   }
491   
492   public void setInStaticContext() {
493     this.inStaticContext = true;
494   }
495   
496   public boolean getInStaticContext() {
497     return this.inStaticContext;
498   }
499 }