001    /* Copyright 2000, 2001, Compaq Computer Corporation */
002    
003    /* =========================================================================
004     * ASTClassFileParser.java
005     * ========================================================================= */
006    
007    package javafe.reader;
008    
009    import java.io.*;
010    import java.util.*;
011    
012    //import decsrc.util.*;
013    import javafe.decsrc.ClassFileParser;
014    
015    import javafe.ast.*;
016    import javafe.util.*;
017    import javafe.genericfile.GenericFile;
018    
019    
020    /* -------------------------------------------------------------------------
021     * ASTClassFileParser
022     * ------------------------------------------------------------------------- */
023    
024    /**
025     * Parses the contents of a class file into an AST for the purpose of
026     * type checking.  Ignores components of the class file that have no
027     * relevance to type checking (e.g. method bodies).
028     */
029    
030    class ASTClassFileParser extends ClassFileParser
031    {
032        /* -- package instance methods ------------------------------------------- */
033    
034        /**
035         * The package name of the class being parsed.
036         * Initialized by constructor (by way of set_this_class)
037         */
038        public Name classPackage;
039    
040        /**
041         * The AST of the class parsed by this parser.
042         * Initialized by constructor (by way of parse_file).
043         */
044        //@ invariant typeDecl != null;
045        //@ invariant typeDecl.specOnly;
046        public TypeDecl typeDecl;
047    
048        /**
049         * A dummy location representing the class being parsed.
050         * Initialized by constructor.
051         */
052        //@ invariant classLocation != Location.NULL;
053        public int classLocation;
054    
055    
056        /**
057         * Vector of methods and fields with Synthetic attributes.
058         * Use this to weed out synthetic while constructing TypeDecl.
059         */
060        /*@ non_null */ private Vector synthetics = new Vector();
061        
062        /**
063         * Flag indicating whether the class being parsed has the synthetic
064         * attribute.
065         */
066        private boolean syntheticClass = false;
067    
068        protected boolean includeBodies;
069    
070        protected boolean omitPrivateFields = true;
071    
072        /**
073         * Parse a class into a new class parser.  Resulting class file is
074         * stored in <code>typeDecl</code>; this will be a "spec only"
075         * declaration.  Its package is stored in <code>classPackage</code>
076         * and a location for it is stored in <code>classLocation</code>.
077         * @param inputFile  the file to parse the class from 
078         * @param includeBodies if true, bodies are included, if not, only a spec is produced */
079        ASTClassFileParser(/*@ non_null */ GenericFile inputFile, boolean includeBodies)
080            throws IOException, ClassFormatError
081        {
082            super();
083            this.includeBodies = includeBodies;
084            DataInputStream stream = null;
085            try {
086                this.inputFile = inputFile;
087                this.classLocation = Location.createWholeFileLoc(inputFile);
088                stream = new DataInputStream(inputFile.getInputStream());
089                parse_file(stream);  //@ nowarn Invariant;  // "parse_file" is a helper
090            } finally {
091                if (stream != null) {
092                    try { stream.close(); }
093                    catch (IOException e) { }
094                }
095            }
096            removeExtraArg();
097        }
098    
099        /** Binary inner class constructors have an extra initial argument to
100            their constructors (the enclosing class).  This is not present in
101            the source file.  To make the AST generated by reading the binary
102            correspond to that obtained from a source file, we remove that
103            extra argument for each inner (non-static) class.  Since we do this
104            at the end of parse_file, each nested class does this for its own
105            direct inner classes. - DRCok
106         */
107        public void removeExtraArg() {
108            TypeDeclElemVec vv = typeDecl.elems;
109            for (int k=0; k<vv.size(); ++k) {
110                if (!(vv.elementAt(k) instanceof ClassDecl)) continue;
111                ClassDecl cd = (ClassDecl)vv.elementAt(k);
112                if (Modifiers.isStatic(cd.modifiers)) continue;
113                TypeDeclElemVec v = cd.elems;
114                for (int j=0; j<v.size(); ++j) {
115                    if (!(v.elementAt(j) instanceof ConstructorDecl)) continue;
116                    ConstructorDecl cdl = (ConstructorDecl)v.elementAt(j);
117                    cdl.args.removeElementAt(0);
118                }
119            }
120        }
121    
122        /* -- protected instance methods ----------------------------------------- */
123    
124        /**
125         * Add only AST nodes that are not synthetic decls to v.
126         * nodes should be an array of TypeDeclElems.  
127         * A synthetic decl is one that had the synthetic attribute, 
128         * or is a static method decl for an
129         * interface.
130         */
131        protected void addNonSyntheticDecls(/*@ non_null */ TypeDeclElemVec v, 
132                                            /*@ non_null */ TypeDeclElem elems[]) { 
133            for (int i = 0; i < elems.length; i++) {
134                if (synthetics.contains(elems[i])) { //@ nowarn;
135                    continue;
136                }
137                if ((modifiers & ACC_INTERFACE) != 0 &&
138                    elems[i] instanceof RoutineDecl) {
139                    RoutineDecl rd = (RoutineDecl)elems[i];
140                    if (Modifiers.isStatic(rd.modifiers)) {
141                        continue;
142                    }
143                }
144                if (omitPrivateFields && elems[i] instanceof FieldDecl) {
145                    if (Modifiers.isPrivate( ((FieldDecl)elems[i]).modifiers )) {
146                        continue;
147                    }
148                }
149                v.addElement(elems[i]);  //@ nowarn Pre;
150            }
151        }
152    
153        /**
154         * Parse the file and set <code>typeDecl</code>.
155         */
156        //@ also ensures typeDecl != null;
157        protected void parse_file(DataInput stream)
158            throws ClassFormatError, IOException
159        {
160            super.parse_file(stream);
161    
162            TypeNameVec interfaceVec =
163                TypeNameVec.make(interfaces); //@ nowarn Pre;
164    
165            int predict = classMembers.size() + routines.length + fields.length;
166            TypeDeclElemVec elementVec = TypeDeclElemVec.make(predict);
167    
168            elementVec.append(classMembers);
169    
170            // only add routines and fields that are not synthetic.
171            this.addNonSyntheticDecls(elementVec, routines);
172            this.addNonSyntheticDecls(elementVec, fields);
173          
174            //@ assume classIdentifier != null;
175            if ((modifiers & ACC_INTERFACE) != 0) {
176                typeDecl= (TypeDecl)InterfaceDecl.make(modifiers&~ACC_INTERFACE,
177                                                       null, classIdentifier,
178                                                       interfaceVec, null, elementVec,
179                                                       classLocation, classLocation,
180                                                       classLocation, classLocation);
181            } else {
182                typeDecl= (TypeDecl)ClassDecl.make(modifiers,
183                                                   null, classIdentifier, 
184                                                   interfaceVec, null, elementVec,
185                                                   classLocation, classLocation,
186                                                   classLocation, classLocation,
187                                                   super_class);
188            }
189            typeDecl.specOnly = true;
190        }
191    
192        /**
193         * Call back from ClassFileParser.
194         */
195        protected void set_version(int major, int minor)
196            throws ClassFormatError
197        {
198            // don't need class file version
199        }
200    
201        /**
202         * Call back from ClassFileParser.
203         */
204        protected void set_num_constants(int cnum)
205            throws ClassFormatError
206        {
207            constants = new Object[cnum];
208            rawConstants = new Object[cnum];
209        }
210    
211        /**
212         * Call back from ClassFileParser.
213         */
214        protected void set_const(int i, int ctype, Object value)
215            throws ClassFormatError
216        {
217            constants[i] = ctype==CONSTANT_Class ?  //@ nowarn IndexTooBig;
218                DescriptorParser.parseClass((String)value) : value;
219            rawConstants[i] = value;
220        }
221    
222        /**
223         * Call back from ClassFileParser.
224         */
225        protected void set_const_ref(int i, int ctype, int class_index,
226                                     String field_name, String type)
227            throws ClassFormatError
228        {
229            // don't need ref constants
230        }
231    
232        /**
233         * Call back from ClassFileParser.
234         */
235        protected void set_class_attribute(String aname,
236                                           DataInput stream, int n)
237            throws IOException, ClassFormatError
238        {
239            if (aname.equals("Synthetic")) {
240                syntheticClass = true;
241            } else if (! aname.equals("InnerClasses")) {
242                super.set_class_attribute(aname, stream, n);
243            } else {
244                int num_classes = stream.readUnsignedShort();
245                for (int j = 0; j < num_classes; j++) {
246                    int inner = stream.readUnsignedShort();
247                    //@ assume inner < constants.length;  // property of class files
248                    int outer = stream.readUnsignedShort();
249                    int name = stream.readUnsignedShort();
250                    //@ assume name < constants.length;  // property of class files
251                    int flags = stream.readUnsignedShort();
252                    //System.out.println("PPP" + Modifiers.toString(flags));
253                    if (outer == this_class_index && name != 0) {
254                        // We've found a member that needs to be parsed...
255                        if (! (rawConstants[name] instanceof String)) {
256                            throw new ClassFormatError("bad constant reference");
257                        }
258                        //@ assume rawConstants[inner] instanceof String;  // property of class files
259                        String nm = (String)rawConstants[inner];
260                        int i = nm.lastIndexOf("/");
261                        String icfn = (i < 0 ? nm : nm.substring(i+1)) + ".class";
262                        GenericFile icf = inputFile.getSibling(icfn);
263                        if (icf == null) {
264                            throw new IOException(icfn + ": inner class not found");
265                        }
266                        ASTClassFileParser parser = new ASTClassFileParser(icf,true);
267                        parser.typeDecl.modifiers |=
268                            (flags & ~ACC_SYNCHRONIZED & ~ACC_INTERFACE);
269          
270                        if (Modifiers.isPublic(parser.typeDecl.modifiers)) {
271                            parser.typeDecl.modifiers &= ~ACC_PROTECTED;
272                        }
273    
274                        // Only add classes that are not synthetic and are not anonymous inner classes,
275                        // which are identified by names that start with a number.
276                        if (!parser.syntheticClass && !Character.isDigit(parser.typeDecl.id.toString().charAt(0))) {
277                            classMembers.addElement(parser.typeDecl);
278                        }
279                    }
280                }
281            }
282        }
283    
284        /**
285         * Call back from ClassFileParser.
286         */
287        protected void set_modifiers(int modifiers)
288            throws ClassFormatError
289        {
290            // The synchronized bit for classes is used for other purposes:
291            this.modifiers = modifiers & ~ACC_SYNCHRONIZED;
292        }
293    
294        /**
295         * Call back from ClassFileParser.
296         */
297        protected void set_this_class(int cindex)
298            throws ClassFormatError
299        {
300            // record the class type and synthesize a location for the class binary
301    
302            TypeName   typeName  = (TypeName)constants[cindex];     //@ nowarn Cast, IndexTooBig;
303            //@ assume typeName != null;
304    
305            Name       qualifier = getNameQualifier(typeName.name);
306            Identifier terminal  = getNameTerminal(typeName.name);
307    
308            this_class_index = cindex;
309            //this_class      = typeName;
310            classPackage    = qualifier;
311            classIdentifier = terminal;
312    
313            // This is not the correct location; it may be useful later, though.
314            //    int        location  = Location.createWholeFileLoc(terminal+".java");
315            //    classLocation   = location;
316    
317            DescriptorParser.classLocation = classLocation;
318        }
319    
320        /**
321         * Call back from ClassFileParser.
322         */
323        protected void set_super_class(int cindex)
324            throws ClassFormatError
325        {
326            super_class = (TypeName)constants[cindex];      //@ nowarn Cast, IndexTooBig;
327        }
328    
329        /**
330         * Call back from ClassFileParser.
331         */
332        protected void set_num_interfaces(int n)
333            throws ClassFormatError
334        {
335            interfaces = new TypeName[n];
336        }
337    
338        /**
339         * Call back from ClassFileParser.
340         */
341        protected void set_interface(int index, int cindex)
342            throws ClassFormatError
343        {
344            interfaces[index] = (TypeName)constants[cindex];        //@ nowarn Cast,IndexTooBig;
345        }
346    
347        /**
348         * Call back from ClassFileParser.
349         */
350        protected void set_num_fields(int n)
351            throws ClassFormatError
352        {
353            fields = new FieldDecl[n];
354        }
355    
356        /**
357         * Call back from ClassFileParser.
358         */
359        protected void set_field(int i, String fname, String type, int mod)
360            throws ClassFormatError
361        {
362            fields[i] =                     //@ nowarn IndexTooBig;
363                FieldDecl.make(mod, null, Identifier.intern(fname),
364                               DescriptorParser.parseField(type), classLocation,
365                               null, classLocation);
366        }
367    
368        /**
369         * Call back from ClassFileParser.
370         */
371        protected void set_field_initializer(int i, Object value)
372            throws ClassFormatError
373        {
374            // construct a literal expression for the initializer
375    
376            FieldDecl field = fields[i];            //@ nowarn IndexTooBig;
377            //@ assume field != null        ;
378    
379            int       tag;
380            Object    literal;
381    
382            switch (field.type.getTag())
383                {
384                case TagConstants.BOOLEANTYPE:
385                    tag     = TagConstants.BOOLEANLIT;
386                    literal = Boolean.valueOf(((Integer)value).intValue() != 0);    //@ nowarn Cast,Null;
387                    break;
388    
389                case TagConstants.INTTYPE:
390                case TagConstants.BYTETYPE:
391                case TagConstants.SHORTTYPE:
392                    tag     = TagConstants.INTLIT;
393                    literal = (Integer)value;     //@ nowarn Cast;
394                    break;
395    
396                case TagConstants.LONGTYPE:
397                    tag     = TagConstants.LONGLIT;
398                    literal = (Long)value;       //@ nowarn Cast;
399                    break;
400    
401                case TagConstants.CHARTYPE:
402                    tag     = TagConstants.CHARLIT;
403                    literal = (Integer)value;    //@ nowarn Cast;
404                    break;
405    
406                case TagConstants.FLOATTYPE:
407                    tag     = TagConstants.FLOATLIT;
408                    literal = (Float)value;     //@ nowarn Cast;
409                    break;
410    
411                case TagConstants.DOUBLETYPE:
412                    tag     = TagConstants.DOUBLELIT;
413                    literal = (Double)value;    //@ nowarn Cast;
414                    break;
415    
416                default:
417                    tag     = TagConstants.STRINGLIT;
418                    literal = (String)value;    //@ nowarn Cast;
419                    break;
420                }
421    
422            field.init = LiteralExpr.make(tag, literal, classLocation);
423        }
424    
425        /**
426         * Call back from ClassFileParser.
427         */
428        protected void set_num_methods(int n)
429            throws ClassFormatError
430        {
431            routines = new RoutineDecl[n];
432        }
433    
434        /**
435         * Call back from ClassFileParser.
436         */
437        protected void set_method(int i, String mname, String sig, int mod)
438            throws ClassFormatError
439        {
440            MethodSignature signature =
441                DescriptorParser.parseMethod(sig);
442            FormalParaDeclVec formalVec =
443                FormalParaDeclVec.make(makeFormals(signature));
444            BlockStmt body = null;
445    
446            routines[i] =                   //@ nowarn IndexTooBig;
447                mname.equals("<init>") ?
448                (RoutineDecl)ConstructorDecl.make(
449                                                  mod, null, null, formalVec, emptyTypeNameVec, body, Location.NULL,
450                                                  classLocation, classLocation, classLocation) :
451                (RoutineDecl)MethodDecl.make(
452                                             mod, null, null, formalVec, emptyTypeNameVec, body, Location.NULL,
453                                             classLocation, classLocation, classLocation,
454                                             Identifier.intern(mname), signature.getReturn(), classLocation);
455        }
456    
457        /**
458         * Call back from ClassFileParser.
459         */
460        protected void set_method_body(int i, int max_stack, int max_local,
461                                       byte[] code, int num_handlers)
462            throws ClassFormatError
463        {
464            // put in a dummy body
465            if (!includeBodies) return;
466            routines[i].body =      //@ nowarn Null, IndexTooBig;
467                BlockStmt.make(StmtVec.make(), classLocation, classLocation);
468            routines[i].locOpenBrace = classLocation;
469        }
470    
471        /**
472         * Call back from ClassFileParser.
473         */
474        protected void set_method_handler(int i, int j, int start_pc, int end_pc,
475                                          int handler_pc, int catch_index)
476            throws ClassFormatError
477        {
478            // don't need method handlers
479        }
480    
481        /**
482         * Call back from ClassFileParser.
483         */
484        protected void set_method_attribute(int i, String aname,
485                                            DataInput stream, int n)
486            throws IOException, ClassFormatError
487        {
488            // look for the Exceptions attribute and modify the appropriate method, if
489            // necessary
490    
491            if (aname.equals("Exceptions")) {
492                routines[i].raises = TypeNameVec.make(parseTypeNames((DataInputStream)stream)); //@ nowarn Null, Cast, IndexTooBig;
493            } else if (aname.equals("Synthetic")) {
494                synthetics.addElement(routines[i]);  //@ nowarn ;
495            } else {
496                stream.skipBytes(n);
497            }
498        }
499    
500        /* -- private instance variables ----------------------------------------- */
501    
502        /**
503         * The input file being parsed.
504         */
505        /*@ non_null */ GenericFile inputFile;
506    
507        /**
508         * The constant pool of the class being parsed.
509         * Initialized by set_num_constants.
510         * Elements initialized by set_const and set_const_ref.
511         *
512         * Dynamic element types according to constant tag:
513         * UTF8                String
514         * String              String
515         * Class               TypeName
516         * Integer             Integer
517         * Float               Float
518         * Long                Long
519         * Double              Double
520         * FieldRef            null
521         * MethodRef           null
522         * InterfaceMethodRef  null
523         */
524        //@ private invariant constants != null;
525        //@ private invariant \typeof(constants) == \type(Object[]);
526        private Object[] constants;
527    
528        /**
529         * The constant pool of the class being parsed.
530         * This array contains the constants as they came out of the
531         * parser (versus translated by DescriptorParser).  Initialized
532         * by set_const and set_num_constants.
533         */
534        //@ private invariant rawConstants != null;
535        //@ private invariant \typeof(rawConstants) == \type(Object[]);
536        //@ private invariant constants.length == rawConstants.length;
537        private Object[] rawConstants;
538    
539        /**
540         * The modifiers of the class being parsed.
541         * Initialized by set_modifiers.
542         */
543        private int modifiers;
544    
545        /**
546         * The contant pool index of this class.
547         * Initialized by set_this_class.
548         */
549        private int this_class_index;
550    
551        /**
552         * The type name of the class being parsed.
553         * Initialized by set_this_class.
554         */
555        //private TypeName this_class;
556    
557        /**
558         * The type name of the superclass of the class being parsed.
559         * Initialized by set_super_class.
560         */
561        private TypeName super_class;
562    
563        /**
564         * The type names of the interfaces implemented by the class being parsed.
565         * Initialized by set_num_interfaces.
566         * Elements initialized by set_interface.
567         */
568        //@ private invariant interfaces != null;
569        //@ private invariant \typeof(interfaces) == \type(TypeName[]);
570        private TypeName[] interfaces;
571    
572        /**
573         * The class members of the class being parsed.
574         * Intialized by set_field, set_method, and set_class_attributes.
575         */
576        //@ invariant classMembers != null;
577        TypeDeclElemVec classMembers = TypeDeclElemVec.make(0);
578    
579        /**
580         * The fields of the class being parsed.
581         * Initialized by set_num_fields.
582         * Elements initialized by set_field.
583         */
584        //@ invariant fields != null;
585        //@ invariant \typeof(fields) == \type(FieldDecl[]);
586        //@ spec_public
587        private FieldDecl[] fields;
588    
589        /**
590         * The methods and constructors of the class being parsed.
591         * Initialized by set_num_methods.
592         * Elements initialized by set_method.
593         */
594        //@ invariant routines != null;
595        //@ invariant \typeof(routines) == \type(RoutineDecl[]);
596        //@ spec_public
597        private RoutineDecl[] routines;
598    
599        /**
600         * The identifier of the class being parsed.
601         * Initialized by set_this_class.
602         */
603        //@ spec_public
604        private Identifier classIdentifier;
605    
606        /* -- private instance methods ------------------------------------------- */
607    
608        /**
609         * Parse a sequence of type names from a given stream.
610         * @param stream                the stream to parse the type names from
611         * @return                      an array of type names
612         * @exception ClassFormatError  if the type names are not class constants
613         */
614        //@ requires stream != null;
615        //@ ensures \nonnullelements(\result);
616        //@ ensures \typeof(\result)==\type(TypeName[]);
617        private TypeName[] parseTypeNames(DataInputStream stream)
618            throws IOException, ClassFormatError
619        {
620            int        count = stream.readUnsignedShort();
621            TypeName[] names = new TypeName[count];
622    
623            for (int i = 0; i<count; i++)
624                {
625                    int index = stream.readUnsignedShort();
626    
627                    if (index>=constants.length)
628                        throw new ClassFormatError("unknown constant");
629    
630                    Object constant = constants[index];
631    
632                    if (!(constant instanceof TypeName))
633                        throw new ClassFormatError("not a class constant");
634    
635                    names[i] = (TypeName)constant;
636                }
637    
638            return names;
639        }
640    
641        /**
642         * Construct a vector of formal parameters from a method signature.
643         * @param signature  the method signature to make the formal parameters from
644         * @return           the formal parameters
645         */
646        //@ requires signature != null;
647        //@ ensures \nonnullelements(\result);
648        //@ ensures \typeof(\result) == \type(FormalParaDecl[]);
649        private FormalParaDecl[] makeFormals(MethodSignature signature)
650        {
651            int              length  = signature.countParameters();
652            FormalParaDecl[] formals = new FormalParaDecl[length];
653    
654            for (int i = 0; i<length; i++) {
655                Identifier id = Identifier.intern("arg" + i);
656                formals[i] =
657                    FormalParaDecl.make(0, null, id, signature.parameterAt(i),
658                                        classLocation);
659            }
660    
661            return formals;
662        }
663    
664        /* -- private class methods ---------------------------------------------- */
665    
666        /**
667         * Return the package qualifier of a given name.
668         * @param name  the name to return the package qualifier of
669         * @return      the package qualifier of name
670         */
671        //@ requires name != null;
672        private static Name getNameQualifier(Name name)
673        {
674            int size = name.size(); 
675    
676            return size>1 ? name.prefix(size-1) : null;
677            // using null for the unnamed package ???
678        }
679    
680        /**
681         * Return the terminal identifier of a given name.
682         * @param name  the name to return the terminal identifier of
683         * @return      the terminal identifier of name
684         */
685        //@ requires name != null;
686        private static Identifier getNameTerminal(Name name)
687        {
688            return name.identifierAt(name.size()-1);
689        }
690    
691        /* -- private class variables -------------------------------------------- */
692    
693        /**
694         * An empty type name vector.
695         */
696        //@ invariant emptyTypeNameVec != null;
697        //@ spec_public
698        private static final TypeNameVec emptyTypeNameVec = TypeNameVec.make();
699    
700        /**
701         * A null identifier.
702         */
703    /* UNUSED
704        //@ invariant nullIdentifier != null;
705        private static final Identifier nullIdentifier = Identifier.intern("");
706    */
707    
708    }
709