001 /* 002 * JastAddJ is covered by the modified BSD License. You should have received a copy of the 003 * modified BSD license with this compiler. 004 * 005 * Copyright (c) 2011, Jesper Öqvist <jesper.oqvist@cs.lth.se> 006 * All rights reserved. 007 */ 008 009 aspect TryWithResources { 010 /** 011 * Syntactic classification for TWR resource declarations. 012 */ 013 eq ResourceDeclaration.getTypeAccess().nameType() = NameType.TYPE_NAME; 014 015 /** 016 * Inherit the lookupType attribute in ResourceDeclaration. 017 */ 018 inh TypeDecl ResourceDeclaration.lookupType(String packageName, String typeName); 019 020 /** 021 * Type checking for TWR. 022 */ 023 public void ResourceDeclaration.typeCheck() { 024 TypeDecl typeAutoCloseable = lookupType("java.lang", "AutoCloseable"); 025 if (typeAutoCloseable == null) 026 error("java.lang.AutoCloseable not found"); 027 else if (!getTypeAccess().type().instanceOf(typeAutoCloseable)) 028 error("Resource specification must declare an AutoCloseable resource"); 029 } 030 031 /*coll Set<TypeDecl> Stmt.uncaughtExceptions() 032 [new HashSet<TypeDecl>()] with add; 033 034 MethodAccess contributes exceptionCollection() 035 to Stmt.uncaughtExceptions();*/ 036 037 /** 038 * Exception error checks. 039 */ 040 public void TryWithResources.exceptionHandling() { 041 042 // Check exception handling of exceptions on auto closing of resource 043 for (ResourceDeclaration resource : getResourceList()) { 044 MethodDecl close = lookupClose(resource); 045 if (close == null) continue; 046 for (Access exception : close.getExceptionList()) { 047 TypeDecl exceptionType = exception.type(); 048 if (!twrHandlesException(exceptionType)) 049 error("automatic closing of resource "+resource.name()+ 050 " may raise the uncaught exception "+exceptionType.fullName()+"; "+ 051 "it must be caught or declared as being thrown"); 052 } 053 } 054 } 055 056 /** 057 * This attribute computes whether or not the TWR statement 058 * has a catch clause which handles the exception. 059 */ 060 syn boolean TryWithResources.catchHandlesException(TypeDecl exceptionType) { 061 for (int i = 0; i < getNumCatchClause(); i++) 062 if (getCatchClause(i).handles(exceptionType)) 063 return true; 064 return false; 065 } 066 067 /** 068 * Returns true if exceptions of type exceptionType are handled 069 * in the try-with-resources statement or any containing statement 070 * within the directly enclosing method or initializer block. 071 */ 072 syn boolean TryWithResources.twrHandlesException(TypeDecl exceptionType) { 073 if (catchHandlesException(exceptionType)) 074 return true; 075 if (hasFinally() && !getFinally().canCompleteNormally()) 076 return true; 077 return handlesException(exceptionType); 078 } 079 080 /** 081 * Inherit the handlesException attribute from methoddecl. 082 */ 083 inh lazy boolean TryWithResources.handlesException(TypeDecl exceptionType); 084 085 eq TryWithResources.getResource(int i).handlesException(TypeDecl exceptionType) = 086 twrHandlesException(exceptionType); 087 088 eq TryWithResources.getBlock().handlesException(TypeDecl exceptionType) = 089 twrHandlesException(exceptionType); 090 091 092 /** 093 * Lookup the close method declaration for the resource which is being used. 094 */ 095 syn MethodDecl TryWithResources.lookupClose(ResourceDeclaration resource) { 096 TypeDecl resourceType = resource.getTypeAccess().type(); 097 for (MethodDecl method : (Collection<MethodDecl>) resourceType.memberMethods("close")) { 098 if (method.getNumParameter() == 0) { 099 return method; 100 } 101 } 102 return null; 103 /* We can't throw a runtime exception here. If there is no close method it 104 * likely means that the resource type is not a subtype of java.lang.AutoCloseable 105 * and type checking will report this error. 106 */ 107 //throw new RuntimeException("close() not found for resource type "+resourceType.fullName()); 108 } 109 110 inh lazy TypeDecl TryWithResources.typeError(); 111 inh lazy TypeDecl TryWithResources.typeRuntimeException(); 112 113 eq TryWithResources.getCatchClause(int childIndex).reachableCatchClause(TypeDecl exceptionType) { 114 for (int i = 0; i < childIndex; i++) 115 if (getCatchClause(i).handles(exceptionType)) 116 return false; 117 if (catchableException(exceptionType)) 118 return true; 119 if (exceptionType.mayCatch(typeError()) || exceptionType.mayCatch(typeRuntimeException())) 120 return true; 121 return false; 122 } 123 124 /** 125 * Variable lookup attribute. 126 */ 127 eq TryWithResources.getBlock().lookupVariable(String name) = localLookup(name); 128 syn lazy SimpleSet TryWithResources.localLookup(String name) { 129 VariableDeclaration v = localVariableDeclaration(name); 130 if (v != null) return v; 131 return lookupVariable(name); 132 } 133 syn lazy VariableDeclaration TryWithResources.localVariableDeclaration(String name) { 134 for (ResourceDeclaration resource : getResourceList()) 135 if (resource.declaresVariable(name)) 136 return resource; 137 return null; 138 } 139 140 TryWithResources implements VariableScope; 141 inh lazy SimpleSet TryWithResources.lookupVariable(String name); 142 eq TryWithResources.getResource(int i).outerScope() = this; 143 144 inh boolean VariableDeclaration.resourcePreviouslyDeclared(String name); 145 inh boolean TryWithResources.resourcePreviouslyDeclared(String name); 146 eq TryWithResources.getResource(int index).resourcePreviouslyDeclared(String name) { 147 for (int i = 0; i < index; ++i) { 148 if (getResource(i).name().equals(name)) 149 return true; 150 } 151 return false; 152 } 153 eq BodyDecl.getChild(int i).resourcePreviouslyDeclared(String name) = false; 154 eq Program.getChild(int i).resourcePreviouslyDeclared(String name) = false; 155 156 public void ResourceDeclaration.nameCheck() { 157 // Special name check for resource specification 158 if (resourcePreviouslyDeclared(name())) 159 error("A resource with the name "+name()+ 160 " has already been declared in this try statement."); 161 162 // Do regular name check for variable declaration 163 super.nameCheck(); 164 } 165 166 // Definite Assignment 167 eq TryWithResources.isDAafter(Variable v) = 168 getBlock().isDAafter(v); 169 170 // 16.2.2 7th bullet 171 eq TryWithResources.getResource(int index).isDAbefore(Variable v) = 172 index == 0 ? isDAbefore(v) : getResource(index - 1).isDAafter(v); 173 eq TryWithResources.getBlock().isDAbefore(Variable v) = 174 getNumResource() == 0 ? isDAbefore(v) : 175 getResource(getNumResource() - 1).isDAafter(v); 176 177 /** 178 * Returns true if the try-with-resources statement can throw 179 * an exception of type (or a subtype of) catchType. 180 */ 181 protected boolean TryWithResources.reachedException(TypeDecl catchType) { 182 boolean found = false; 183 // found is true if the exception type is caught by a catch clause 184 for(int i = 0; i < getNumCatchClause() && !found; i++) 185 if(getCatchClause(i).handles(catchType)) 186 found = true; 187 // if an exception is thrown in the block and the exception is not caught and 188 // either there is no finally block or the finally block can complete normally 189 if(!found && (!hasFinally() || getFinally().canCompleteNormally()) ) 190 if(catchableException(catchType)) 191 return true; 192 // even if the exception is caught by the catch clauses they may 193 // throw new exceptions 194 for(int i = 0; i < getNumCatchClause(); i++) 195 if(getCatchClause(i).reachedException(catchType)) 196 return true; 197 return hasFinally() && getFinally().reachedException(catchType); 198 } 199 200 /** 201 * True if the automatic closing of resources in this try-with-resources statement 202 * may throw an exception of type catchType. 203 */ 204 syn boolean TryWithResources.resourceClosingException(TypeDecl catchType) { 205 for (ResourceDeclaration resource : getResourceList()) { 206 MethodDecl close = lookupClose(resource); 207 if (close == null) continue; 208 for (Access exception : close.getExceptionList()) { 209 TypeDecl exceptionType = exception.type(); 210 if (catchType.mayCatch(exception.type())) 211 return true; 212 } 213 } 214 return false; 215 } 216 217 /** 218 * True if the resource initialization of this try-with-resources statement 219 * may throw an exception of type catchType. 220 */ 221 syn boolean TryWithResources.resourceInitializationException(TypeDecl catchType) { 222 for (ResourceDeclaration resource : getResourceList()) { 223 if (resource.reachedException(catchType)) 224 return true; 225 } 226 return false; 227 } 228 229 /** 230 * @see AST.TryStmt#catchableException(TypeDecl) TryStmt.catchableException(TypeDecl) 231 */ 232 eq TryWithResources.catchableException(TypeDecl type) = 233 getBlock().reachedException(type) || 234 resourceClosingException(type) || 235 resourceInitializationException(type); 236 237 eq ResourceModifiers.isFinal() = true; 238 } 239 240 aspect PrettyPrint { 241 /** 242 * Pretty printing of try-with-resources 243 */ 244 public void TryWithResources.toString(StringBuffer sb) { 245 sb.append(indent() + "try ("); 246 for (ResourceDeclaration resource : getResourceList()) { 247 sb.append(resource.toString()); 248 } 249 sb.append(") "); 250 getBlock().toString(sb); 251 for (CatchClause cc : getCatchClauseList()) { 252 sb.append(" "); 253 cc.toString(sb); 254 } 255 if (hasFinally()) { 256 sb.append(" finally "); 257 getFinally().toString(sb); 258 } 259 } 260 261 } 262