001 /* 002 * The JastAdd Extensible Java Compiler (http://jastadd.org) is covered 003 * by the modified BSD License. You should have received a copy of the 004 * modified BSD license with this compiler. 005 * 006 * Copyright (c) 2005-2008, Torbjorn Ekman 007 * All rights reserved. 008 */ 009 010 aspect ExceptionHandling { 011 012 // exception types 013 eq Program.getChild().typeException() = lookupType("java.lang", "Exception"); 014 inh lazy TypeDecl TypeDecl.typeException(); 015 eq Program.getChild().typeRuntimeException() = lookupType("java.lang", "RuntimeException"); 016 inh lazy TypeDecl TypeDecl.typeRuntimeException(); 017 eq Program.getChild().typeError() = lookupType("java.lang", "Error"); 018 inh lazy TypeDecl TypeDecl.typeError(); 019 eq Program.getChild().typeNullPointerException() = lookupType("java.lang", "NullPointerException"); 020 inh lazy TypeDecl ThrowStmt.typeNullPointerException(); 021 eq Program.getChild().typeThrowable() = lookupType("java.lang", "Throwable"); 022 inh lazy TypeDecl BodyDecl.typeThrowable(); 023 024 syn lazy boolean TypeDecl.isException() = instanceOf(typeException()); 025 026 /** 027 * Unfortunately the concept of checked vs. unchecked exceptions 028 * has been inverted in JastAddJ compared to the Java specification. 029 * This is a slightly unfortunate design flaw which we cannot change 030 * at this time. 031 */ 032 syn lazy boolean TypeDecl.isCheckedException() = isException() && 033 (instanceOf(typeRuntimeException()) || instanceOf(typeError())); 034 035 /** 036 * Unfortunately the concept of checked vs. unchecked exceptions 037 * has been inverted in JastAddJ compared to the Java specification. 038 * This is a slightly unfortunate design flaw which we cannot change 039 * at this time. 040 */ 041 syn lazy boolean TypeDecl.isUncheckedException() = isException() && !isCheckedException(); 042 043 inh boolean MethodAccess.handlesException(TypeDecl exceptionType); 044 inh boolean ConstructorAccess.handlesException(TypeDecl exceptionType); 045 inh lazy boolean ThrowStmt.handlesException(TypeDecl exceptionType); 046 inh lazy boolean InstanceInitializer.handlesException(TypeDecl exceptionType); 047 inh lazy boolean StaticInitializer.handlesException(TypeDecl exceptionType); 048 inh boolean FieldDeclaration.handlesException(TypeDecl exceptionType); 049 inh lazy boolean TryStmt.handlesException(TypeDecl exceptionType); 050 inh lazy boolean ConstructorDecl.handlesException(TypeDecl exceptionType); 051 inh lazy boolean MethodDecl.handlesException(TypeDecl exceptionType); 052 inh boolean ClassInstanceExpr.handlesException(TypeDecl exceptionType); 053 054 public void ASTNode.exceptionHandling() { 055 } 056 057 public void MethodAccess.exceptionHandling() { 058 for(Iterator iter = exceptionCollection().iterator(); iter.hasNext(); ) { 059 TypeDecl exceptionType = (TypeDecl)iter.next(); 060 if(!handlesException(exceptionType)) 061 error("" + decl().hostType().fullName() + "." + this + " invoked in " + hostType().fullName() + " may throw uncaught exception " + exceptionType.fullName()); 062 } 063 } 064 065 syn lazy Collection MethodAccess.exceptionCollection() { 066 //System.out.println("Computing exceptionCollection for " + name()); 067 HashSet set = new HashSet(); 068 Iterator iter = decls().iterator(); 069 if(!iter.hasNext()) 070 return set; 071 072 MethodDecl m = (MethodDecl)iter.next(); 073 //System.out.println("Processing first found method " + m.signature() + " in " + m.hostType().fullName()); 074 075 for(int i = 0; i < m.getNumException(); i++) { 076 TypeDecl exceptionType = m.getException(i).type(); 077 set.add(exceptionType); 078 } 079 while(iter.hasNext()) { 080 HashSet first = new HashSet(); 081 first.addAll(set); 082 HashSet second = new HashSet(); 083 m = (MethodDecl)iter.next(); 084 //System.out.println("Processing the next method " + m.signature() + " in " + m.hostType().fullName()); 085 for(int i = 0; i < m.getNumException(); i++) { 086 TypeDecl exceptionType = m.getException(i).type(); 087 second.add(exceptionType); 088 } 089 set = new HashSet(); 090 for(Iterator i1 = first.iterator(); i1.hasNext(); ) { 091 TypeDecl firstType = (TypeDecl)i1.next(); 092 for(Iterator i2 = second.iterator(); i2.hasNext(); ) { 093 TypeDecl secondType = (TypeDecl)i2.next(); 094 if(firstType.instanceOf(secondType)) { 095 set.add(firstType); 096 } 097 else if(secondType.instanceOf(firstType)) { 098 set.add(secondType); 099 } 100 } 101 } 102 } 103 return set; 104 } 105 106 public void ClassDecl.exceptionHandling() { 107 constructors(); 108 super.exceptionHandling(); 109 } 110 111 public void ConstructorAccess.exceptionHandling() { 112 for(int i = 0; i < decl().getNumException(); i++) { 113 TypeDecl exceptionType = decl().getException(i).type(); 114 if(!handlesException(exceptionType)) 115 error("" + this + " may throw uncaught exception " + exceptionType.fullName()); 116 } 117 } 118 119 public void ClassInstanceExpr.exceptionHandling() { 120 for (Access exception : decl().getExceptionList()) { 121 TypeDecl exceptionType = exception.type(); 122 if (!handlesException(exceptionType)) 123 error("" + this + " may throw uncaught exception " + 124 exceptionType.fullName() + "; it must be caught or declared as being thrown"); 125 } 126 } 127 128 public void ThrowStmt.exceptionHandling() { 129 TypeDecl exceptionType = getExpr().type(); 130 if(exceptionType == typeNull()) 131 exceptionType = typeNullPointerException(); 132 // 8.4.4 133 if(!handlesException(exceptionType)) 134 error("" + this + " throws uncaught exception " + exceptionType.fullName()); 135 } 136 137 eq Program.getChild().handlesException(TypeDecl exceptionType) { 138 throw new Error("Operation handlesException not supported"); 139 } 140 eq CompilationUnit.getTypeDecl().handlesException(TypeDecl exceptionType) = 141 !exceptionType.isUncheckedException(); 142 143 eq MethodDecl.getBlock().handlesException(TypeDecl exceptionType) = 144 throwsException(exceptionType) || handlesException(exceptionType); 145 146 syn lazy boolean MethodDecl.throwsException(TypeDecl exceptionType) { 147 for(int i = 0; i < getNumException(); i++) 148 if(exceptionType.instanceOf(getException(i).type())) 149 return true; 150 return false; 151 } 152 153 eq ConstructorDecl.getBlock().handlesException(TypeDecl exceptionType) = 154 throwsException(exceptionType) || handlesException(exceptionType); 155 156 eq ConstructorDecl.getConstructorInvocation().handlesException(TypeDecl exceptionType) = 157 throwsException(exceptionType) || handlesException(exceptionType); 158 159 syn lazy boolean ConstructorDecl.throwsException(TypeDecl exceptionType) { 160 for(int i = 0; i < getNumException(); i++) 161 if(exceptionType.instanceOf(getException(i).type())) 162 return true; 163 return false; 164 } 165 166 eq FieldDeclaration.getInit().handlesException(TypeDecl exceptionType) { 167 if(hostType().isAnonymous()) 168 return true; 169 if(!exceptionType.isUncheckedException()) 170 return true; 171 for(Iterator iter = hostType().constructors().iterator(); iter.hasNext(); ) { 172 ConstructorDecl decl = (ConstructorDecl)iter.next(); 173 if(!decl.throwsException(exceptionType)) 174 return false; 175 } 176 return true; 177 } 178 179 // 8.6 180 eq InstanceInitializer.getBlock().handlesException(TypeDecl exceptionType) { 181 if(hostType().isAnonymous()) 182 return true; 183 if(!exceptionType.isUncheckedException()) 184 return true; 185 for(Iterator iter = hostType().constructors().iterator(); iter.hasNext(); ) { 186 ConstructorDecl decl = (ConstructorDecl)iter.next(); 187 if(!decl.throwsException(exceptionType)) 188 return false; 189 } 190 return true; 191 } 192 193 eq StaticInitializer.getBlock().handlesException(TypeDecl exceptionType) = 194 hostType().isAnonymous() ? handlesException(exceptionType) : !exceptionType.isUncheckedException(); 195 196 eq TryStmt.getCatchClause().handlesException(TypeDecl exceptionType) { 197 if(hasFinally() && !getFinally().canCompleteNormally()) 198 return true; 199 return handlesException(exceptionType); 200 } 201 202 eq TryStmt.getBlock().handlesException(TypeDecl exceptionType) { 203 for(int i = 0; i < getNumCatchClause(); i++) 204 if(getCatchClause(i).handles(exceptionType)) 205 return true; 206 if(hasFinally() && !getFinally().canCompleteNormally()) 207 return true; 208 return handlesException(exceptionType); 209 } 210 211 // the catch clause catches the exception 212 syn boolean CatchClause.handles(TypeDecl exceptionType) = false; 213 eq BasicCatch.handles(TypeDecl exceptionType) = 214 !getParameter().type().isUnknown() 215 && exceptionType.instanceOf(getParameter().type()); 216 217 /** 218 * The block of the try statement can throw an exception of 219 * a type assignable to the given type. 220 */ 221 syn lazy boolean TryStmt.catchableException(TypeDecl type) = 222 getBlock().reachedException(type); 223 224 protected boolean ASTNode.reachedException(TypeDecl type) { 225 for(int i = 0; i < getNumChild(); i++) 226 if(getChild(i).reachedException(type)) 227 return true; 228 return false; 229 } 230 231 protected boolean TryStmt.reachedException(TypeDecl type) { 232 boolean found = false; 233 // found is true if the exception type is caught by a catch clause 234 for(int i = 0; i < getNumCatchClause() && !found; i++) 235 if(getCatchClause(i).handles(type)) 236 found = true; 237 // if an exception is thrown in the block and the exception is not caught and 238 // either there is no finally block or the finally block can complete normally 239 if(!found && (!hasFinally() || getFinally().canCompleteNormally()) ) 240 if(getBlock().reachedException(type)) 241 return true; 242 // even if the exception is caught by the catch clauses they may 243 // throw new exceptions 244 for(int i = 0; i < getNumCatchClause(); i++) 245 if(getCatchClause(i).reachedException(type)) 246 return true; 247 return hasFinally() && getFinally().reachedException(type); 248 } 249 250 syn lazy boolean TypeDecl.mayCatch(TypeDecl thrownType) = 251 thrownType.instanceOf(this) || this.instanceOf(thrownType); 252 253 protected boolean MethodAccess.reachedException(TypeDecl catchType) { 254 for(Iterator iter = exceptionCollection().iterator(); iter.hasNext(); ) { 255 TypeDecl exceptionType = (TypeDecl)iter.next(); 256 if(catchType.mayCatch(exceptionType)) 257 return true; 258 } 259 return super.reachedException(catchType); 260 } 261 262 protected boolean ThrowStmt.reachedException(TypeDecl catchType) { 263 TypeDecl exceptionType = getExpr().type(); 264 if(exceptionType == typeNull()) 265 exceptionType = typeNullPointerException(); 266 if(catchType.mayCatch(exceptionType)) 267 return true; 268 return super.reachedException(catchType); 269 } 270 271 // 8.8.4 (8.4.4) 272 protected boolean ConstructorAccess.reachedException(TypeDecl catchType) { 273 for(int i = 0; i < decl().getNumException(); i++) { 274 TypeDecl exceptionType = decl().getException(i).type(); 275 if(catchType.mayCatch(exceptionType)) 276 return true; 277 } 278 return super.reachedException(catchType); 279 } 280 281 protected boolean ClassInstanceExpr.reachedException(TypeDecl catchType) { 282 ConstructorDecl decl = decl(); 283 for(int i = 0; i < decl.getNumException(); i++) { 284 TypeDecl exceptionType = decl.getException(i).type(); 285 if(catchType.mayCatch(exceptionType)) 286 return true; 287 } 288 for(int i = 0; i < getNumArg(); i++) { 289 if(getArg(i).reachedException(catchType)) 290 return true; 291 } 292 return false; 293 } 294 295 }