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