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