    001    /* Copyright 2000, 2001, Compaq Computer Corporation */
    002
    003    package escjava.translate;
    004
    005    import javafe.ast.*;
    006    import javafe.util.*;
    007
    008    import escjava.ast.*;
    009    import escjava.ast.TagConstants;
    010
    011    /**
    012     * Handles turning off warnings.
    013     */
    014
    015    public class NoWarn
    016    {
    017        /***************************************************
    018         *                                                 *
    019         * Global nowarns:                                 *
    020         *                                                 *
    021         ***************************************************/
    022
    023        //@ spec_public
    024        static private final int chkStatus[]
    025                = new int[TagConstants.LASTESCCHECKTAG -
    026                          TagConstants.FIRSTESCCHECKTAG + 1];
    027        //@ public invariant chkStatus != null;
    028
    029        static {
    030            init();
    031        }
    032
    033        static public void init() {
    034            useGlobalStatus = false;
    035            setAllChkStatus(TagConstants.CHK_AS_ASSERT);
    036            setChkStatus(TagConstants.CHKUNEXPECTEDEXCEPTION2, TagConstants.CHK_AS_ASSUME);
    037        }
    038
    039        public static void setAllChkStatus(int status) {
    040            for (int i = TagConstants.FIRSTESCCHECKTAG;
    041                 i <= TagConstants.LASTESCCHECKTAG; i++) {
    042                setChkStatus(i, status);
    043            }
    044
    045            // We never check Free because we know they always hold, even
    046            // if we can't prove them:
    047            setChkStatus( TagConstants.CHKFREE, TagConstants.CHK_AS_SKIP );
    048            setChkStatus( TagConstants.CHKASSUME, TagConstants.CHK_AS_ASSUME );
    049            setChkStatus( TagConstants.CHKADDINFO, TagConstants.CHK_AS_ASSUME );
    050        }
    051
    052        // If this boolean is set to true, all checks will use the the
    053        // globalStatus check tag.
    054        public static boolean useGlobalStatus = false;
    055
    056        // This will be set to one of the three kinds of checking
    057        // (CHK_AS_ASSERT/ASSUME/SKIP).
    058        /*@ invariant globalStatus == TagConstants.CHK_AS_ASSUME ||
    059          @           globalStatus == TagConstants.CHK_AS_ASSERT ||
    060          @           globalStatus == TagConstants.CHK_AS_SKIP;
    061          @*/
    062        public static int globalStatus;
    063
    064        /**
    065         * Sets how the check tag should be interpreted.  tag should be
    066         * one of the CHK... constants defined in TagConstants, and status
    067         * should be one of CHK_AS_ASSUME/CHK_AS_ASSERT/CHK_AS_SKIP.
    068         */
    069        /*@ requires TagConstants.FIRSTESCCHECKTAG <= tag &&
    070          @          tag <= TagConstants.LASTESCCHECKTAG;
    071          @ requires status == TagConstants.CHK_AS_ASSUME || status == TagConstants.CHK_AS_ASSERT ||
    072          @          status == TagConstants.CHK_AS_SKIP;
    073          @ ensures chkStatus[tag - TagConstants.FIRSTESCCHECKTAG] == status;
    074          @*/
    075        public static void setChkStatus( int tag, int status ) {
    076            Assert.notFalse( TagConstants.FIRSTESCCHECKTAG <= tag
    077                             && tag <= TagConstants.LASTESCCHECKTAG );
    078
    079            Assert.notFalse( status == TagConstants.CHK_AS_ASSUME
    080                             || status == TagConstants.CHK_AS_ASSERT
    081                             || status == TagConstants.CHK_AS_SKIP );
    082
    083            chkStatus[ tag - TagConstants.FIRSTESCCHECKTAG ] = status;
    084        }
    085
    086        /**
    087         * @return how the check tag should be interpreted.  tag should be
    088         * one of the CHK... constants defined in TagConstants. The result
    089         * is be one of CHK_AS_ASSUME/CHK_AS_ASSERT/CHK_AS_SKIP.
    090         */
    091        /*@ requires TagConstants.FIRSTESCCHECKTAG <= tag &&
    092          @          tag <= TagConstants.LASTESCCHECKTAG;
    093          @*/
    094        public static int getChkStatus( int tag ) {
    095            Assert.notFalse( TagConstants.FIRSTESCCHECKTAG <= tag
    096                             && tag <= TagConstants.LASTESCCHECKTAG );
    097            // Use the globalStatus if the flag is set
    098            if (useGlobalStatus)
    099                return globalStatus;
    100            else
    101                return chkStatus[ tag - TagConstants.FIRSTESCCHECKTAG ];
    102        }
    103
    104        /**
    105         * Convert a nowarn category to its tag.  Returns 0 if the String
    106         * is not a valid nowarn category.
    107         */
    108        public static int toNoWarnTag(String name) {
    109            for (int i = TagConstants.FIRSTESCCHECKTAG;
    110                 i <= TagConstants.LASTESCCHECKTAG; i++) {
    111                if (TagConstants.toString(i).equals(name)
    112                    && i != TagConstants.CHKFREE)
    113                    return i;
    114            }
    115            return 0;
    116        }
    117
    118        /**
    119         * The line # and streamId to nowarn before (cf. setStartLine).
    120         */
    121        private static int noWarnStreamId = -1;
    122        private static int startLine = -1;  // no nowarn by default
    123
    124        /**
    125         * Set a nowarn to ignore all lines before a given line in a given
    126         * CompilationUnit.
    127         *
    128         * <p> Future calls to this routine remove any previous nowarns
    129         * established via this routine. </p>
    130         *
    131         * @param line passing a line # of -1 acts as a no-op nowarn.
    132         */
    133        public static void setStartLine(int line, /*@ non_null */ CompilationUnit cu) {
    134            startLine = line;
    135            noWarnStreamId = Location.toStreamId(cu.loc);
    136        }
    137
    138        /***************************************************
    139         *                                                 *
    140         * Registering nowarns annotations and checking    *
    141         * that they are legal ones.                       *
    142         *                                                 *
    143         ***************************************************/
    144
    145        static private /*@ non_null @*/ LexicalPragmaVec nowarns = LexicalPragmaVec.make();
    146
    147        public static void registerNowarns(LexicalPragmaVec v) {
    148            if (v != null)
    149                nowarns.append(v);
    150        }
    151
    152        /**
    153         * Type checks the registered nowarn pragmas, reporting errors to
    154         * {@link ErrorSet} appropriately.
    155         */
    156        public static void typecheckRegisteredNowarns() {
    157            for (int i = 0; i < nowarns.size(); i++) {
    158                LexicalPragma lp = nowarns.elementAt(i);
    159                if (lp instanceof NowarnPragma) {
    160                    NowarnPragma np = (NowarnPragma)lp;
    161                    IdentifierVec iv = np.checks;
    162                    for (int j = 0; j < iv.size(); j++) {
    163                        String nowarnName = iv.elementAt(j).toString();
    164                        if (toNoWarnTag(nowarnName) == 0) {
    165                            ErrorSet.error(np.loc, "'" + nowarnName +
    166                                           "' is not a legal warning category");
    167                        }
    168                    }
    169                }
    170            }
    171        }
    172
    173        /***************************************************
    174         *                                                 *
    175         * Comparing locations:                            *
    176         *                                                 *
    177         ***************************************************/
    178
    179        /**
    180         * Is <code>loc</code> on a given line number in a given stream?
    181         *
    182         * @param loc may be <code>Location.NULL</code>, in which case
    183         * <code>false</code> is returned.
    184         */
    185        static boolean onLine(int loc, int lineNo, int streamId) {
    186            if (loc==Location.NULL)
    187                return false;
    188
    189            return (streamId == Location.toStreamId(loc))
    190                && (lineNo == Location.toLineNumber(loc));
    191        }
    192
    193        /**
    194         * Is a given line # in a given stream (id) before (exclusive)
    195         * the line that contains a given location?
    196         *
    197         * @param loc if Location.NULL, then no is returned.
    198         */
    199        static boolean beforeLine(int loc, int lineNo, int streamId) {
    200            if (loc==Location.NULL)
    201                return false;
    202
    203            if (Location.toStreamId(loc) != streamId)
    204                return false;
    205
    206            return (Location.toLineNumber(loc) < lineNo);
    207        }
    208
    209        /**
    210         * Is a given line # in a given stream (id) between the lines that
    211         * contain the two given locations (inclusive)? <p>
    212         *
    213         * @param startLoc
    214         * @param endLoc
    215         * @param lineNo
    216         * @param streamId
    217         */
    218        //@ requires (* the two locations must be from the same stream. *);
    219        static boolean inRange(int startLoc, int endLoc, int lineNo,
    220                               int streamId) {
    221            if (startLoc==Location.NULL || endLoc==Location.NULL)
    222                return false;
    223
    224            // Check startLoc...endLoc in streamId:
    225            if (Location.toStreamId(startLoc) != streamId)
    226                return false;
    227            Assert.notFalse(Location.toStreamId(endLoc)==streamId);
    228
    229            return (Location.toLineNumber(startLoc) <= lineNo) &&
    230                (lineNo <= Location.toLineNumber(endLoc));
    231        }
    232
    233        /***************************************************
    234         *                                                 *
    235         * Check nonwarn status:                           *
    236         *                                                 *
    237         ***************************************************/
    238
    239        /**
    240         * Returns how the check tag should be interpreted.  tag should be
    241         * one of the CHK... constants defined in TagConstants. The result
    242         * is one of CHK_AS_ASSUME/CHK_AS_ASSERT/CHK_AS_SKIP.
    243         */
    244        /*@ requires TagConstants.FIRSTESCCHECKTAG <= tag &&
    245          @          tag <= TagConstants.LASTESCCHECKTAG;
    246          @*/
    247        public static int getChkStatus(int tag, int locUse, int locPragmaDecl) {
    248            Assert.notFalse( TagConstants.FIRSTESCCHECKTAG <= tag
    249                             && tag <= TagConstants.LASTESCCHECKTAG );
    250
    251            // If uncommented, display the ranges of each check:
    252            // displayWarningRange(tag, locUse, locPragmaDecl);
    253
    254            // Use the globalStatus if the flag is set
    255            if (useGlobalStatus)
    256                return globalStatus;
    257
    258            // Check for startLine nowarn:
    259            if (beforeLine(locUse, startLine, noWarnStreamId))
    260                return TagConstants.CHK_AS_ASSUME;
    261
    262            // check nowarns
    263            for( int i=0; i<nowarns.size(); i++ ) {
    264                LexicalPragma lp = nowarns.elementAt(i);
    265                if( lp instanceof NowarnPragma ) {
    266
    267                    NowarnPragma np = (NowarnPragma)lp;
    268                    int nowarnStreamId = Location.toStreamId(np.loc);
    269                    int nowarnLineNo = Location.toLineNumber(np.loc);
    270
    271                    if( onLine(locUse, nowarnLineNo, nowarnStreamId) ||
    272                        onLine(locPragmaDecl, nowarnLineNo, nowarnStreamId) )
    273                    {
    274                        // on same line
    275                        if( np.checks == null || np.checks.size() == 0 ) {
    276                            // applies to all checks
    277                            return TagConstants.CHK_AS_ASSUME;
    278                        }
    279
    280                        // search thru listed checks
    281                        String chkStr = TagConstants.toString(tag);
    282
    283                        for( int j=0; j<np.checks.size(); j++ )
    284                            if( chkStr.equals( np.checks.elementAt(j).toString() ) ) {
    285                                // no warn on this tag
    286                                return TagConstants.CHK_AS_ASSUME;
    287                            }
    288                    }
    289                }
    290            }
    291
    292            // no line-specific nowarn
    293            // check general table
    294
    295            return chkStatus[ tag - TagConstants.FIRSTESCCHECKTAG ];
    296        }
    297    } // end of class NoWarn
    298
    299    /*
    300     * Local Variables:
    301     * Mode: Java
    302     * fill-column: 85
    303     * End:
    304     */
    305
    306