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