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