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