    001    /* Copyright 2000, 2001, Compaq Computer Corporation */
    002
    003    package javafe;
    004
    005    import java.util.Vector;
    006    import java.util.Iterator;
    007    import java.util.ArrayList;
    008
    009    import javafe.ast.*;
    010    import javafe.tc.*;
    011    import javafe.util.*;
    012    import javafe.genericfile.GenericFile;
    013    import javafe.genericfile.NormalGenericFile;
    014
    015    import java.io.BufferedReader;
    016    import java.io.FileReader;
    017    import java.io.IOException;
    018
    019    /**
    020     * <code>SrcTool</code> is an abstract class for tools that use
    021     * our Java front end to process the <code>CompilationUnit</code>s
    022     * found in source files. <p>
    023     *
    024     * It adds to <code>FrontEndTool</code> code for processing a series of
    025     * source files specified on the command line.
    026     *
    027     * If processRecursively is set, then files are processed
    028     * recursively.  (I.e., files loaded in the course of processing one
    029     * file are also processed.)<p>
    030     *
    031     * The remaining processing, if any, is front-end-tool specific.<p>
    032     */
    033
    034    public abstract class SrcTool extends FrontEndTool implements Listener
    035    {
    036
    037        /***************************************************
    038         *                                                 *
    039         * Keeping track of loaded CompilationUnits:       *
    040         *                                                 *
    041         **************************************************/
    042
    043        /**
    044         * A list of all the <code>CompilationUnit</code>s we have loaded
    045         * so far.  This list is extended automatically at the end as new
    046         * <code>CompilationUnit</code>s are loaded using notification from
    047         * <code>OutsideEnv</code>.
    048         */
    049        //@ invariant loaded != null;
    050        //@ invariant loaded.elementType == \type(CompilationUnit);
    051        //@ invariant !loaded.containsNull;
    052        //@ invariant loaded.owner == this;
    053        public Vector loaded = new Vector();
    054
    055        public SrcTool() {
    056            super();
    057
    058            //@ set loaded.elementType = \type(CompilationUnit);
    059            //@ set loaded.containsNull = false;
    060            //@ set loaded.owner = this;
    061        }
    062
    063
    064        /**
    065         * Add a <code>CompilationUnit</code> to <code>loaded</code>. <p>
    066         *
    067         * This should only be called by <code>OutsideEnv</code> using the
    068         * <code>Listener</code> interface.<p>
    069         */
    070        public void notify(CompilationUnit justLoaded) {
    071            if (!justLoaded.duplicate) loaded.addElement(justLoaded);
    072        }
    073
    074
    075        /***************************************************
    076         *                                                 *
    077         * Main processing code:                           *
    078         *                                                 *
    079         **************************************************/
    080
    081        public Options makeOptions() {
    082            return new SrcToolOptions();
    083        }
    084
    085        private static SrcToolOptions options() {
    086            return (SrcToolOptions)options;
    087        }
    088
    089        /**
    090         * Main processing loop for <code>SrcTool</code>. <p>
    091         *
    092         * The remaining arguments are <code>args[offset]</code>,
    093         * <code>args[offset+1]</code>, ...<p>
    094         *
    095         * This method calls preload, loadAllFiles, postload, preprocess, handleAllCU, postprocess.
    096         */
    097        public void frontEndToolProcessing(ArrayList args) {
    098            long startTime = currentTime();
    099            /*
    100             * At this point, all options have already been processed and
    101             * the front end has been initialized.
    102             */
    103
    104            preload();
    105
    106            loadAllFiles(args);
    107
    108            postload();
    109
    110            // Do any tool-specific pre-processing:
    111            preprocess();
    112
    113            if (!options.quiet)
    114                    System.out.println("    [" + timeUsed(startTime) + "]");
    115
    116            handleAllCUs();
    117
    118            // Do any tool-specific post-processing:
    119            postprocess();
    120        }
    121
    122
    123        /***************************************************
    124         *                                                 *
    125         * SrcTool-instance specific processing:           *
    126         *                                                 *
    127         **************************************************/
    128
    129        public void loadAllFiles(ArrayList args) {
    130            ArrayList accumulatedResults = new ArrayList(args.size());
    131            Iterator i = args.iterator();
    132            while (i.hasNext()) {
    133                InputEntry ie = (InputEntry)i.next();
    134                ArrayList a = resolveInputEntry(ie);
    135                OutsideEnv.addSources(a);
    136            }
    137        }
    138
    139        //@ ensures \result.elementType <: \type(GenericFile);
    140        public ArrayList resolveInputEntry(InputEntry iee) {
    141            InputEntry ie = iee;
    142            if (ie.contents == null) {
    143                ie = ie.resolve();
    144                if (!ie.auto) {
    145                    String s = ie.verify();
    146                    if (s != null) {
    147                        ErrorSet.error(s);
    148                        ie.contents = new ArrayList(0);
    149                        return ie.contents;
    150                    }
    151                }
    152                if (ie instanceof FileInputEntry) {
    153                    ie.contents = new ArrayList(1);
    154                    ie.contents.add(new NormalGenericFile(ie.name));
    155                } else if (ie instanceof DirInputEntry) {
    156                    ie.contents = OutsideEnv.resolveDirSources(ie.name);
    157                } else if (ie instanceof PackageInputEntry) {
    158                    String[] pa = javafe.filespace.StringUtil.parseList(ie.name,'.');
    159                    ie.contents = OutsideEnv.resolveSources(pa);
    160                } else if (ie instanceof ClassInputEntry) {
    161                    ie.contents = new ArrayList(1);
    162                    int p = ie.name.lastIndexOf('.');
    163                    if (p == -1) {
    164                        GenericFile gf = OutsideEnv.reader.findType(
    165                                    new String[0],ie.name);
    166                        ie.contents.add(gf);
    167                    } else if (p==0 || p == ie.name.length()-1) {
    168                        ErrorSet.error("Invalid type name: " + ie.name);
    169                        ie.contents = new ArrayList(0);
    170                    } else {
    171                        String[] pa = javafe.filespace.StringUtil.parseList(
    172                                        ie.name.substring(0,p),'.');
    173                        GenericFile gf = OutsideEnv.reader.findType(pa,
    174                                        ie.name.substring(p+1));
    175                        ie.contents.add(gf);
    176                    }
    177                } else if (ie instanceof ListInputEntry) {
    178                    ie.contents = resolveList(ie.name);
    179                } else {
    180                    ErrorSet.caution("Skipping unknown (or not found) input item: "
    181                            + ie.name);
    182                    ie.contents = new ArrayList(0);
    183                }
    184            }
    185            return ie.contents;
    186        }
    187
    188        public void loadInputEntry(InputEntry ie) {
    189            OutsideEnv.addSources(resolveInputEntry(ie));
    190        }
    191
    192        //@ requires argumentFileName != null;
    193        //@ ensures \result.elementType <: \type(GenericFile);
    194        public ArrayList resolveList(String argumentFileName) {
    195            /* load in source files from supplied file name */
    196            ArrayList list = new ArrayList();
    197            try {
    198                BufferedReader in = null;
    199                try {
    200                    in = new BufferedReader(
    201                            new FileReader(argumentFileName));
    202                    String s;
    203                    while ((s = in.readLine()) != null) {
    204                        // allow blank lines in files list
    205                        if (!s.equals("")) {
    206                            ArrayList a = (resolveInputEntry(InputEntry.make(s)));
    207                            if (a != null) list.addAll(a);
    208                        }
    209                    }
    210                } finally {
    211                    if (in != null) in.close();
    212                }
    213            } catch (IOException e) {
    214                ErrorSet.error("I/O failure while reading argument list file "
    215                        + argumentFileName + ": " + e.getMessage());
    216            }
    217            return list;
    218        }
    219
    220    /*
    221        public void resolvePackages(ArrayList packagesToProcess) {
    222            Iterator i = packagesToProcess.iterator();
    223            while (i.hasNext()) {
    224                String p = (String)i.next();
    225            }
    226        }
    227    */
    228        /** Iterates, calling handleCU for each loaded CU.
    229         */
    230        public void handleAllCUs() {
    231            /*
    232             * Call handleCU on the resulting loaded CompilationUnits.
    233             *
    234             * If processRecursively is true, then continue calling handleCU
    235             * on loaded CompilationUnits that have not had handleCU called
    236             * on them in the order they were loaded until no such
    237             * CompilationUnits remain.  (handleCU may load CompilationUnits
    238             * indirectly.)
    239             */
    240            int i=0;
    241            for (int end=loaded.size(); i<end; i++) {
    242                handleCU((CompilationUnit)loaded.elementAt(i));
    243                if (options().processRecursively) {
    244                            Assert.notFalse(OutsideEnv.avoidSpec == true);
    245                            end = loaded.size();
    246                }
    247            }
    248        }
    249
    250        /**
    251         * Hook for any work needed before any files are loaded.
    252         */
    253        public void preload() {
    254            // Set up to receive CompilationUnit-loading notification events:
    255            OutsideEnv.setListener(this);
    256        }
    257
    258        /**
    259         * Called for any work after loading files
    260         */
    261    // FIXME - can this be done at preload time?
    262        public void postload() {
    263            OutsideEnv.avoidSpec = options().avoidSpec;
    264            if (options().processRecursively)
    265                OutsideEnv.avoidSpec = true;
    266        }
    267
    268        /**
    269         * Hook for any work needed after files are loaded
    270         * but before <code>handleCU</code> is called
    271         * on each <code>CompilationUnit</code> to process them.
    272         */
    273        public void preprocess() {}
    274
    275        /**
    276         * Hook for any work needed after <code>handleCU</code> has been called
    277         * on each <code>CompilationUnit</code> to process them.
    278         */
    279        public void postprocess() {}
    280
    281
    282        /**
    283         * This method is called on each <code>CompilationUnit</code>
    284         * that this tool processes. <p>
    285         *
    286         * The default implementation is simply to call
    287         * <code>handleTD</code> on each <code>TypeDecl</code> present in
    288         * cu.  It is intended that subclassers override this method.<p>
    289         */
    290        //@ requires cu != null;
    291        public void handleCU(CompilationUnit cu) {
    292                    // Iterate over all the TypeDecls representing outside types in cu:
    293                    TypeDeclVec elems = cu.elems;
    294                    for (int i=0; i<elems.size(); i++) {
    295                        TypeDecl d = elems.elementAt(i);
    296
    297                        handleTD(d);
    298                    }
    299        }
    300
    301
    302        /**
    303         * This method is called on the TypeDecl of each
    304         * outside type that SrcTool is to process. <p>
    305         */
    306        //@ requires td != null;
    307        public void handleTD(TypeDecl td) {}
    308
    309    }