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