    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