001 /* 002 * JastAddJ is covered by the modified BSD License. You should have received 003 * a copy of the 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 PreciseRethrow { 010 011 syn Collection<TypeDecl> Expr.throwTypes() { 012 Collection<TypeDecl> tts = new LinkedList<TypeDecl>(); 013 tts.add(type()); 014 return tts; 015 } 016 eq VarAccess.throwTypes() = decl().throwTypes(); 017 syn lazy Collection<TypeDecl> VariableDeclaration.throwTypes() { 018 Collection<TypeDecl> tts = new LinkedList<TypeDecl>(); 019 tts.add(type()); 020 return tts; 021 } 022 syn lazy Collection<TypeDecl> FieldDeclaration.throwTypes() { 023 Collection<TypeDecl> tts = new LinkedList<TypeDecl>(); 024 tts.add(type()); 025 return tts; 026 } 027 syn lazy Collection<TypeDecl> ParameterDeclaration.throwTypes() { 028 if (isCatchParam() && effectivelyFinal()) { 029 // the catch parameter must be final or implicitly 030 // final (multi-catch) 031 return catchClause().caughtExceptions(); 032 } else { 033 Collection<TypeDecl> tts = new LinkedList<TypeDecl>(); 034 tts.add(type()); 035 return tts; 036 } 037 } 038 syn lazy Collection<TypeDecl> CatchParameterDeclaration.throwTypes() = 039 catchClause().caughtExceptions(); 040 041 syn boolean ParameterDeclaration.effectivelyFinal() = 042 isFinal() || !inhModifiedInScope(this); 043 044 /** 045 * @return true if the variable var is modified in the local scope 046 */ 047 inh boolean ParameterDeclaration.inhModifiedInScope(Variable var); 048 eq ConstructorDecl.getParameter().inhModifiedInScope(Variable var) = 049 getBlock().modifiedInScope(var); 050 eq MethodDecl.getParameter().inhModifiedInScope(Variable var) = 051 getBlock().modifiedInScope(var); 052 eq BasicCatch.getParameter().inhModifiedInScope(Variable var) = 053 getBlock().modifiedInScope(var); 054 055 syn boolean Stmt.modifiedInScope(Variable var); 056 eq VarDeclStmt.modifiedInScope(Variable var) = false; 057 eq VariableDeclaration.modifiedInScope(Variable var) = false; 058 eq EmptyStmt.modifiedInScope(Variable var) = false; 059 eq LabeledStmt.modifiedInScope(Variable var) = 060 getStmt().modifiedInScope(var); 061 eq ExprStmt.modifiedInScope(Variable var) = 062 getExpr().modifiedInScope(var); 063 eq Block.modifiedInScope(Variable var) { 064 for (Stmt stmt : getStmtList()) 065 if (stmt.modifiedInScope(var)) 066 return true; 067 return false; 068 } 069 eq SwitchStmt.modifiedInScope(Variable var) = 070 getBlock().modifiedInScope(var); 071 eq Case.modifiedInScope(Variable var) = false; 072 eq BreakStmt.modifiedInScope(Variable var) = false; 073 eq ContinueStmt.modifiedInScope(Variable var) = false; 074 eq ReturnStmt.modifiedInScope(Variable var) = false; 075 eq ThrowStmt.modifiedInScope(Variable var) = false; 076 eq IfStmt.modifiedInScope(Variable var) { 077 if (getThen().modifiedInScope(var)) 078 return true; 079 return hasElse() && getElse().modifiedInScope(var); 080 } 081 eq WhileStmt.modifiedInScope(Variable var) = 082 getStmt().modifiedInScope(var); 083 eq DoStmt.modifiedInScope(Variable var) = 084 getStmt().modifiedInScope(var); 085 eq ForStmt.modifiedInScope(Variable var) { 086 for (Stmt stmt : getInitStmtList()) 087 if (stmt.modifiedInScope(var)) 088 return true; 089 for (Stmt stmt : getUpdateStmtList()) 090 if (stmt.modifiedInScope(var)) 091 return true; 092 return getStmt().modifiedInScope(var); 093 } 094 eq EnhancedForStmt.modifiedInScope(Variable var) = 095 getStmt().modifiedInScope(var); 096 eq SynchronizedStmt.modifiedInScope(Variable var) = 097 getBlock().modifiedInScope(var); 098 eq TryStmt.modifiedInScope(Variable var) { 099 if (getBlock().modifiedInScope(var)) 100 return true; 101 for (CatchClause cc : getCatchClauseList()) 102 if (cc.modifiedInScope(var)) 103 return true; 104 return hasFinally() && getFinally().modifiedInScope(var); 105 } 106 eq AssertStmt.modifiedInScope(Variable var) = false; 107 eq LocalClassDeclStmt.modifiedInScope(Variable var) = false; 108 109 syn boolean CatchClause.modifiedInScope(Variable var) = 110 getBlock().modifiedInScope(var); 111 syn boolean Expr.modifiedInScope(Variable var) = false; 112 eq AssignExpr.modifiedInScope(Variable var) = 113 getDest().isVariable(var); 114 115 syn boolean Expr.isVariable(Variable var) = false; 116 eq VarAccess.isVariable(Variable var) = decl() == var; 117 118 /** 119 * @return true if this is the parameter declaration of a catch clause 120 */ 121 inh boolean ParameterDeclaration.isCatchParam(); 122 eq Program.getChild(int i).isCatchParam() = false; 123 eq ConstructorDecl.getParameter().isCatchParam() = false; 124 eq MethodDecl.getParameter().isCatchParam() = false; 125 eq BasicCatch.getParameter().isCatchParam() = true; 126 127 inh CatchClause ParameterDeclaration.catchClause(); 128 inh CatchClause CatchParameterDeclaration.catchClause(); 129 130 eq Program.getChild(int i).catchClause() { 131 throw new IllegalStateException("Could not find parent " + 132 "catch clause"); 133 } 134 eq CatchClause.getChild(int i).catchClause() = this; 135 136 inh Collection<TypeDecl> CatchClause.caughtExceptions(); 137 138 eq TryStmt.getCatchClause(int index).caughtExceptions() { 139 Collection<TypeDecl> excp = new HashSet<TypeDecl>(); 140 getBlock().collectExceptions(excp, this); 141 Collection<TypeDecl> caught = new LinkedList<TypeDecl>(); 142 Iterator<TypeDecl> iter = excp.iterator(); 143 while (iter.hasNext()) { 144 TypeDecl exception = iter.next(); 145 // this catch clause handles the exception 146 if (!getCatchClause(index).handles(exception)) 147 continue; 148 // no previous catch clause handles the exception 149 boolean already = false; 150 for (int i = 0; i < index; ++i) { 151 if (getCatchClause(i).handles(exception)) { 152 already = true; 153 break; 154 } 155 } 156 if (!already) { 157 caught.add(exception); 158 } 159 } 160 return caught; 161 } 162 163 refine ExceptionHandling 164 public void ThrowStmt.exceptionHandling() { 165 Collection<TypeDecl> exceptionTypes = getExpr().throwTypes(); 166 for (TypeDecl exceptionType : exceptionTypes) { 167 if (exceptionType == typeNull()) 168 exceptionType = typeNullPointerException(); 169 // 8.4.4 170 if (!handlesException(exceptionType)) 171 error(""+this+" throws uncaught exception "+ 172 exceptionType.fullName()); 173 } 174 } 175 176 refine ExceptionHandling 177 protected boolean ThrowStmt.reachedException(TypeDecl catchType) { 178 Collection<TypeDecl> exceptionTypes = getExpr().throwTypes(); 179 boolean reached = false; 180 for (TypeDecl exceptionType : exceptionTypes) { 181 if(exceptionType == typeNull()) 182 exceptionType = typeNullPointerException(); 183 if(catchType.mayCatch(exceptionType)) { 184 reached = true; 185 break; 186 } 187 if (super.reachedException(catchType)) { 188 reached = true; 189 break; 190 } 191 } 192 return reached; 193 } 194 195 inh boolean CatchClause.reportUnreachable(); 196 eq CatchClause.getBlock().reportUnreachable() = false; 197 198 void BasicCatch.checkUnreachableStmt() { 199 if (!getBlock().reachable() && reportUnreachable()) 200 error("the exception "+getParameter().type().fullName()+ 201 " is not thrown in the body of the try statement"); 202 } 203 204 void MultiCatch.checkUnreachableStmt() { 205 if (!getBlock().reachable() && reportUnreachable()) 206 error("the exception "+getParameter().type().fullName()+ 207 " is not thrown in the body of the try statement"); 208 } 209 }