001    package AST;
002    
003    import java.util.HashSet;
004    import java.io.File;
005    import java.util.*;
006    import beaver.*;
007    import java.util.ArrayList;
008    import java.util.zip.*;
009    import java.io.*;
010    import java.io.FileNotFoundException;
011    import java.util.Collection;
012    /**
013      * @ast class
014     * 
015     */
016    public class Attributes extends java.lang.Object {
017    
018        protected BytecodeParser p;
019    
020    
021        protected boolean isSynthetic;
022    
023    
024    
025        protected Attributes(BytecodeParser parser) {
026          p = parser;
027          isSynthetic = false;
028        }
029    
030    
031    
032        protected void processAttribute(String attribute_name, int attribute_length) {
033          if(attribute_name.equals("Synthetic")) {
034            isSynthetic = true;
035          } else {
036            this.p.skip(attribute_length);
037          }
038        }
039    
040    
041    
042        protected void attributes() {
043          int attributes_count = p.u2();
044          if(BytecodeParser.VERBOSE)
045            p.println("    " + attributes_count + " attributes:");
046          for (int j = 0; j < attributes_count; j++) {
047            int attribute_name_index = p.u2();
048            int attribute_length = p.u4();
049            String attribute_name = p.getCONSTANT_Utf8_Info(attribute_name_index).string();
050            if(BytecodeParser.VERBOSE)
051              p.println("    Attribute: " + attribute_name + ", length: "
052                  + attribute_length);
053            processAttribute(attribute_name, attribute_length);
054          }
055        }
056    
057    
058    
059        public boolean isSynthetic() {
060          return isSynthetic;
061        }
062    
063    
064    
065        // 4.8.15.1
066        protected ElementValue readElementValue() {
067          char c = (char)p.u1();
068          switch (c) {
069            case 'e':
070              int type_name_index = this.p.u2();
071              String type_name = this.p.getCONSTANT_Utf8_Info(type_name_index).string();
072              // remove inital L and trailing ;
073              Access typeAccess = this.p.fromClassName(type_name.substring(1, type_name.length() - 1));
074              int const_name_index = this.p.u2();
075              String const_name = this.p.getCONSTANT_Utf8_Info(const_name_index).string();
076              return new ElementConstantValue(typeAccess.qualifiesAccess(new VarAccess(const_name)));
077            case 'B': case 'C': case 'D': case 'F': case 'I': case 'J': case 'S': case 'Z': case 's':
078              int const_value_index = p.u2();
079              Expr e = this.p.getCONSTANT_Info(const_value_index).expr();
080              return new ElementConstantValue(e);
081            case 'c':
082              int class_info_index = p.u2();
083              String descriptor = this.p.getCONSTANT_Utf8_Info(class_info_index).string();
084              e = new TypeDescriptor(p, descriptor).type();
085              return new ElementConstantValue(e);
086            case '@':
087              return new ElementAnnotationValue(readAnnotation());
088            case '[':
089              int index = p.u2();
090              List list = new List();
091              for(int i = 0; i < index; i++) 
092                list.add(readElementValue());
093              return new ElementArrayValue(list);
094            default:
095              throw new Error("AnnotationDefault tag " + c + " not supported");
096          }
097        }
098    
099    
100    
101        // 4.8.15
102        protected Annotation readAnnotation() {
103          Access typeAccess = new FieldDescriptor(p, "").type();
104          int num_element_value_pairs = p.u2();
105          List list = new List();
106          for(int i = 0; i < num_element_value_pairs; i++) {
107            int element_name_index = p.u2();
108            String element_name = p.getCONSTANT_Utf8_Info(element_name_index).string();
109            ElementValue element_value = readElementValue();
110            list.add(new ElementValuePair(element_name, element_value));
111          }
112          return new Annotation("Annotation", typeAccess, list);
113        }
114    
115    
116    
117        public static class FieldAttributes extends Attributes {
118          protected CONSTANT_Info constantValue;
119          public java.util.ArrayList annotations;
120          public Signatures.FieldSignature fieldSignature;
121          public FieldAttributes(BytecodeParser p) {
122            super(p);
123            attributes();
124          }
125    
126          protected void processAttribute(String attribute_name, int attribute_length) {
127            if(attribute_name.equals("ConstantValue") && attribute_length == 2) {
128              int constantvalue_index = p.u2();
129              constantValue = p.getCONSTANT_Info(constantvalue_index);
130            }
131            else if(attribute_name.equals("RuntimeVisibleAnnotations")) {
132              int num_annotations = p.u2();
133              if(annotations == null)
134                annotations = new java.util.ArrayList();
135              for(int j = 0; j < num_annotations; j++)
136                annotations.add(readAnnotation());
137            }
138            else if(attribute_name.equals("RuntimeInvisibleAnnotations")) {
139              int num_annotations = p.u2();
140              if(annotations == null)
141                annotations = new java.util.ArrayList();
142              for(int j = 0; j < num_annotations; j++)
143                annotations.add(readAnnotation());
144            }
145            else if(attribute_name.equals("Signature")) {
146              int signature_index = p.u2();
147              String s = p.getCONSTANT_Utf8_Info(signature_index).string();
148              fieldSignature = new Signatures.FieldSignature(s);
149            }
150            else {
151              super.processAttribute(attribute_name, attribute_length);
152            }
153          }
154    
155          public CONSTANT_Info constantValue() {
156            return constantValue;
157          }
158        }
159    
160    
161    
162        public static class MethodAttributes extends Attributes {
163          protected List exceptionList;
164          protected ElementValue elementValue;
165          public Signatures.MethodSignature methodSignature;
166          public java.util.ArrayList annotations;
167          public java.util.ArrayList[] parameterAnnotations;
168    
169          public MethodAttributes(BytecodeParser p) {
170            super(p);
171            attributes();
172          }
173    
174          protected void processAttribute(String attribute_name, int attribute_length) {
175            if(attribute_name.equals("Exceptions")) {
176              parseExceptions();
177            } 
178            else if(attribute_name.equals("AnnotationDefault")) {
179              annotationDefault();
180            }
181            else if(attribute_name.equals("Signature")) {
182              int signature_index = p.u2();
183              String s = p.getCONSTANT_Utf8_Info(signature_index).string();
184              methodSignature = new Signatures.MethodSignature(s);
185            }
186            else if(attribute_name.equals("RuntimeVisibleAnnotations")) {
187              int num_annotations = p.u2();
188              if(annotations == null)
189                annotations = new java.util.ArrayList();
190              for(int j = 0; j < num_annotations; j++)
191                annotations.add(readAnnotation());
192            }
193            else if(attribute_name.equals("RuntimeInvisibleAnnotations")) {
194              int num_annotations = p.u2();
195              if(annotations == null)
196                annotations = new java.util.ArrayList();
197              for(int j = 0; j < num_annotations; j++)
198                annotations.add(readAnnotation());
199            }
200            else if(attribute_name.equals("RuntimeVisibleParameterAnnotations")) {
201              int num_parameters = p.u1();
202              if(parameterAnnotations == null)
203                parameterAnnotations = new java.util.ArrayList[num_parameters];
204              for(int i = 0; i < num_parameters; i++) {
205                if(parameterAnnotations[i] == null)
206                  parameterAnnotations[i] = new java.util.ArrayList();
207                int num_annotations = p.u2();
208                for(int j = 0; j < num_annotations; j++)
209                  parameterAnnotations[i].add(readAnnotation());
210              }
211            }
212            else if(attribute_name.equals("RuntimeInvisibleParameterAnnotations")) {
213              int num_parameters = p.u1();
214              if(parameterAnnotations == null)
215                parameterAnnotations = new java.util.ArrayList[num_parameters];
216              for(int i = 0; i < num_parameters; i++) {
217                if(parameterAnnotations[i] == null)
218                  parameterAnnotations[i] = new java.util.ArrayList();
219                int num_annotations = p.u2();
220                for(int j = 0; j < num_annotations; j++)
221                  parameterAnnotations[i].add(readAnnotation());
222              }
223            }
224            /*
225            else if(attribute_name.equals("RuntimeVisibleExtendedAnnotations")) {
226              int num_annotations = p.u2();
227              java.util.ArrayList extendedAnnotations = new java.util.ArrayList();
228              for(int j = 0; j < num_annotations; j++) {
229                extendedAnnotations.add(readAnnotation());
230              }
231              int kind = p.u1();
232              if(kind == 0x06)
233                System.out.println("Found receiver annotation");
234              if(kind >= 0x00 && kind <= 0x05) // typecast, instaceof, new
235                p.u2(); // skip 2
236              else if(kind == 0x08 || kind == 0x09) { // local variable
237                int table_length = p.u2();
238                for(int i = 0; i < table_length; i++)
239                  p.skip(6);
240              }
241              else if(kind >= 0x10 && kind <= 0x13) // bound
242                p.skip(2);
243              else if(kind >= 0x14 && kind <= 0x15) // extends, implements
244                p.skip(1);
245              else if(kind >= 0x16 && kind <= 0x17) // throws
246                p.skip(1);
247    
248    
249              this.p.skip(attribute_length);
250            }
251            */
252            else {
253              super.processAttribute(attribute_name, attribute_length);
254            }
255          }
256    
257          private void parseExceptions() {
258            int number_of_exceptions = p.u2();
259            exceptionList = new List();
260            if(BytecodeParser.VERBOSE)
261              p.println("      " + number_of_exceptions + " exceptions:");
262            for (int i = 0; i < number_of_exceptions; i++) {
263              CONSTANT_Class_Info exception = p.getCONSTANT_Class_Info(p.u2());
264              if(BytecodeParser.VERBOSE)
265                p.println("        exception " + exception.name());
266              exceptionList.add(exception.access());
267            }
268          }
269    
270          public List exceptionList() {
271            return exceptionList != null ? exceptionList : new List();
272          }
273    
274          public ElementValue elementValue() {
275            return elementValue;
276          }
277    
278          // 4.8.19
279          private void annotationDefault() {
280            elementValue = readElementValue();
281          }
282    
283        }
284    
285    
286    
287        public static class TypeAttributes extends Attributes {
288          TypeDecl typeDecl;
289          TypeDecl outerTypeDecl;
290          Program classPath;
291          
292          private boolean isInnerClass;
293       
294          public TypeAttributes(BytecodeParser p, TypeDecl typeDecl, TypeDecl outerTypeDecl, Program classPath) {
295            super(p);
296            this.typeDecl = typeDecl;
297            this.outerTypeDecl = outerTypeDecl;
298            this.classPath = classPath;
299            attributes();
300          }
301    
302         public boolean isInnerClass() {
303                 return isInnerClass;
304         }
305         
306          protected void processAttribute(String attribute_name, int attribute_length) {
307            if(attribute_name.equals("InnerClasses")) {
308              innerClasses();
309            }
310            else if(attribute_name.equals("Signature")) {
311              int signature_index = p.u2();
312              String s = p.getCONSTANT_Utf8_Info(signature_index).string();
313              Signatures.ClassSignature classSignature = new Signatures.ClassSignature(s);
314              typeDecl = typeDecl.makeGeneric(classSignature);
315            }
316            else if(attribute_name.equals("RuntimeVisibleAnnotations")) {
317              int num_annotations = p.u2();
318              //System.out.println("RuntimeVisibleAnnotations: " + num_annotations);
319              for(int j = 0; j < num_annotations; j++) {
320                Annotation a = readAnnotation();
321                typeDecl.getModifiers().addModifier(a);
322              }
323            }
324            else if(attribute_name.equals("RuntimeInvisibleAnnotations")) {
325              int num_annotations = p.u2();
326              //System.out.println("RuntimeInvisibleAnnotations: " + num_annotations);
327              for(int j = 0; j < num_annotations; j++) {
328                Annotation a = readAnnotation();
329                typeDecl.getModifiers().addModifier(a);
330              }
331            }
332            else {
333              super.processAttribute(attribute_name, attribute_length);
334            }
335          }
336    
337        protected void innerClasses() {
338                 int number_of_classes = this.p.u2();
339                 if(BytecodeParser.VERBOSE)
340                         p.println("    Number of classes: " + number_of_classes);
341                 for (int i = 0; i < number_of_classes; i++) {
342                         if(BytecodeParser.VERBOSE)
343                                 p.print("      " + i + "(" + number_of_classes + ")" +  ":");
344                         int inner_class_info_index = this.p.u2();
345                         int outer_class_info_index = this.p.u2();
346                         int inner_name_index = this.p.u2();
347                         int inner_class_access_flags = this.p.u2();
348                         if(inner_class_info_index > 0) {
349                                 CONSTANT_Class_Info inner_class_info = this.p.getCONSTANT_Class_Info(inner_class_info_index);
350                                 String inner_class_name = inner_class_info.name();
351                                         String inner_name = inner_class_name.substring(inner_class_name.lastIndexOf("$")+1);
352                                 String outer_class_name;
353                                 if (outer_class_info_index > 0) {
354                                         CONSTANT_Class_Info outer_class_info = this.p.getCONSTANT_Class_Info(outer_class_info_index);
355                                         if(inner_class_info == null || outer_class_info == null) {
356                                                 System.out.println("Null");
357                                         }
358                                         outer_class_name = outer_class_info.name();
359    
360                                         if(BytecodeParser.VERBOSE)
361                                                 this.p.println("      inner: " + inner_class_name + ", outer: " + outer_class_name);
362    
363                                 } else {
364                                         //anonymous inner class; need to infer outer_class_name from inner_class_name
365                                         outer_class_name = inner_class_name.substring(0,inner_class_name.lastIndexOf("$"));
366                                 }
367                                 if (inner_class_info.name().equals(p.classInfo.name())) {
368                                         if(BytecodeParser.VERBOSE)
369                                                 p.println("      Class " + inner_class_name + " is inner (" + inner_name + ")");
370                                         typeDecl.setID(inner_name);
371                                         typeDecl.setModifiers(BytecodeParser.modifiers(inner_class_access_flags & 0x041f));
372                                         if (this.p.outerClassName != null && this.p.outerClassName.equals(outer_class_name)) {
373                                                 MemberTypeDecl m = null;
374                                                 if (typeDecl instanceof ClassDecl) {
375                                                         m = new MemberClassDecl((ClassDecl)typeDecl);
376                                                         outerTypeDecl.addBodyDecl(m);
377                                                 } else if (typeDecl instanceof InterfaceDecl) {
378                                                         m = new MemberInterfaceDecl((InterfaceDecl)typeDecl);
379                                                         outerTypeDecl.addBodyDecl(m);
380                                                 }
381                                         } else {
382                                                 isInnerClass = true;
383                                         }
384                                 }
385                                 if (outer_class_name.equals(this.p.classInfo.name())) {
386                                         if(BytecodeParser.VERBOSE)
387                                                 p.println("      Class " + this.p.classInfo.name()
388                                                                 + " has inner class: " + inner_class_name);
389                                         if(BytecodeParser.VERBOSE)
390                                                 p.println("Begin processing: " + inner_class_name);
391                                         try {
392                                                 java.io.InputStream is=null;
393                                                 try{
394                                                         is = classPath.getInputStream(inner_class_name);
395                                                 } catch(Error e) {
396                                                         if(e.getMessage().startsWith("Could not find nested type")) {
397                                                                 //ignore
398                                                         } else {
399                                                                 throw e;
400                                                         }
401                                                 }
402                                                 if(is != null) {
403                                                         BytecodeParser p = new BytecodeParser(is, this.p.name);
404                                                         p.parse(typeDecl, outer_class_name, classPath, (inner_class_access_flags & Flags.ACC_STATIC) == 0);
405                                                         is.close();
406                                                 }
407                                                 else {
408                                                         p.println("Error: ClassFile " + inner_class_name
409                                                                         + " not found");
410                                                 }
411                                         } catch (FileNotFoundException e) {
412                                                 System.out.println("Error: " + inner_class_name
413                                                                 + " not found");
414                                         } catch (Exception e) {
415                                                 e.printStackTrace();
416                                                 System.exit(1);
417                                         }
418                                         if(BytecodeParser.VERBOSE)
419                                                 p.println("End processing: " + inner_class_name);
420                                 }
421                         }
422    
423                 }
424                 if(BytecodeParser.VERBOSE)
425                         p.println("    end");
426          }
427        }
428    
429    
430    }