001 /* Copyright (c) 2005-2008, Torbjorn Ekman 002 * All rights reserved. 003 * 004 * Redistribution and use in source and binary forms, with or without 005 * modification, are permitted provided that the following conditions are met: 006 * 007 * 1. Redistributions of source code must retain the above copyright notice, 008 * this list of conditions and the following disclaimer. 009 * 010 * 2. Redistributions in binary form must reproduce the above copyright notice, 011 * this list of conditions and the following disclaimer in the documentation 012 * and/or other materials provided with the distribution. 013 * 014 * 3. Neither the name of the copyright holder nor the names of its 015 * contributors may be used to endorse or promote products derived from this 016 * software without specific prior written permission. 017 * 018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 021 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 022 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 028 * POSSIBILITY OF SUCH DAMAGE. 029 */ 030 031 aspect UnreachableStatements { 032 033 void ASTNode.checkUnreachableStmt() { 034 } 035 void Stmt.checkUnreachableStmt() { 036 if (!reachable() && reportUnreachable()) { 037 error("statement is unreachable"); 038 } 039 } 040 void StaticInitializer.checkUnreachableStmt() { 041 if (!getBlock().canCompleteNormally()) { 042 errorf("static initializer in %s can not complete normally", hostType().fullName()); 043 } 044 } 045 void InstanceInitializer.checkUnreachableStmt() { 046 if (!getBlock().canCompleteNormally()) { 047 errorf("instance initializer in %s can not complete normally", hostType().fullName()); 048 } 049 } 050 051 inh boolean Stmt.reachable(); 052 inh boolean Block.reachable(); 053 syn lazy boolean Stmt.canCompleteNormally() = true; 054 055 eq ConstructorDecl.getParsedConstructorInvocation().reachable() = true; 056 eq ConstructorDecl.getImplicitConstructorInvocation().reachable() = true; 057 058 // NB we only check the parsed constructor invocation since an implicit one should always complete normally! 059 eq ConstructorDecl.getBlock().reachable() = 060 !hasParsedConstructorInvocation() 061 ? true 062 : getParsedConstructorInvocation().canCompleteNormally(); 063 064 eq MethodDecl.getBlock().reachable() = true; 065 eq StaticInitializer.getBlock().reachable() = true; 066 eq InstanceInitializer.getBlock().reachable() = true; 067 068 eq Block.canCompleteNormally() = 069 getNumStmt() == 0 070 ? reachable() 071 : getStmt(getNumStmt() - 1).canCompleteNormally(); 072 eq Block.getStmt(int index).reachable() = 073 index == 0 074 ? reachable() 075 : getStmt(index-1).canCompleteNormally(); 076 077 eq LocalClassDeclStmt.canCompleteNormally() = reachable(); 078 079 eq VarDeclStmt.canCompleteNormally() = reachable(); 080 081 eq EmptyStmt.canCompleteNormally() = reachable(); 082 083 eq LabeledStmt.canCompleteNormally() = getStmt().canCompleteNormally() || reachableBreak(); 084 eq LabeledStmt.getStmt().reachable() = reachable(); 085 086 syn lazy boolean BranchTargetStmt.reachableBreak() { 087 for (Iterator iter = targetBreaks().iterator(); iter.hasNext(); ) { 088 BreakStmt stmt = (BreakStmt) iter.next(); 089 if (stmt.reachable()) { 090 return true; 091 } 092 } 093 return false; 094 } 095 096 eq ExprStmt.canCompleteNormally() = reachable(); 097 098 syn boolean SwitchStmt.lastStmtCanCompleteNormally() = getBlock().canCompleteNormally(); 099 100 syn boolean SwitchStmt.noStmts() { 101 for (int i = 0; i < getBlock().getNumStmt(); i++) { 102 if (!(getBlock().getStmt(i) instanceof Case)) { 103 return false; 104 } 105 } 106 return true; 107 } 108 109 syn boolean SwitchStmt.noStmtsAfterLastLabel() = 110 getBlock().getNumStmt() > 0 111 && getBlock().getStmt(getBlock().getNumStmt()-1) instanceof Case; 112 113 syn boolean SwitchStmt.noDefaultLabel() { 114 for (int i = 0; i < getBlock().getNumStmt(); i++) { 115 if (getBlock().getStmt(i) instanceof DefaultCase) { 116 return false; 117 } 118 } 119 return true; 120 } 121 122 eq SwitchStmt.canCompleteNormally() = 123 lastStmtCanCompleteNormally() || noStmts() 124 || noStmtsAfterLastLabel() 125 || noDefaultLabel() || reachableBreak(); 126 127 eq SwitchStmt.getBlock().reachable() = reachable(); 128 129 syn boolean Case.reachable() = 130 getParent().getParent() instanceof Block && ((Block) getParent().getParent()).reachable(); 131 132 eq WhileStmt.canCompleteNormally() = 133 reachable() && (!getCondition().isConstant() || !getCondition().isTrue()) || reachableBreak(); 134 135 eq WhileStmt.getStmt().reachable() = reachable() && !getCondition().isFalse(); 136 137 eq DoStmt.canCompleteNormally() = 138 getStmt().canCompleteNormally() && (!getCondition().isConstant() || !getCondition().isTrue()) 139 || reachableContinue() && (!getCondition().isConstant() || !getCondition().isTrue()) 140 || reachableBreak(); 141 142 syn lazy boolean BranchTargetStmt.reachableContinue() { 143 for (Iterator iter = targetContinues().iterator(); iter.hasNext(); ) { 144 Stmt stmt = (Stmt) iter.next(); 145 if (stmt.reachable()) { 146 return true; 147 } 148 } 149 return false; 150 } 151 152 eq DoStmt.getStmt().reachable() = reachable(); 153 154 eq ForStmt.canCompleteNormally() = 155 reachable() && hasCondition() 156 && (!getCondition().isConstant() || !getCondition().isTrue()) || reachableBreak(); 157 158 eq ForStmt.getStmt().reachable() = 159 reachable() 160 && (!hasCondition() || (!getCondition().isConstant() || !getCondition().isFalse())); 161 162 eq BreakStmt.canCompleteNormally() = false; 163 eq ContinueStmt.canCompleteNormally() = false; 164 eq ReturnStmt.canCompleteNormally() = false; 165 eq ThrowStmt.canCompleteNormally() = false; 166 167 eq SynchronizedStmt.canCompleteNormally() = getBlock().canCompleteNormally(); 168 eq SynchronizedStmt.getBlock().reachable() = reachable(); 169 170 eq TryStmt.canCompleteNormally() { 171 boolean anyCatchClauseCompleteNormally = false; 172 for (int i = 0; i < getNumCatchClause() && !anyCatchClauseCompleteNormally; i++) { 173 anyCatchClauseCompleteNormally = getCatchClause(i).getBlock().canCompleteNormally(); 174 } 175 return (getBlock().canCompleteNormally() || anyCatchClauseCompleteNormally) && 176 (!hasNonEmptyFinally() || getFinally().canCompleteNormally()); 177 } 178 eq TryStmt.getBlock().reachable() = reachable(); 179 eq TryStmt.getFinally().reachable() = reachable(); 180 eq BasicCatch.getBlock().reachable() = reachableCatchClause(getParameter().type()); 181 182 /** 183 * @return true if an exception of type exceptionType is catchable by the catch clause 184 */ 185 inh lazy boolean CatchClause.reachableCatchClause(TypeDecl exceptionType); 186 eq TryStmt.getCatchClause(int childIndex).reachableCatchClause(TypeDecl exceptionType) { 187 for (int i = 0; i < childIndex; i++) { 188 if (getCatchClause(i).handles(exceptionType)) { 189 return false; 190 } 191 } 192 if (catchableException(exceptionType)) { 193 return true; 194 } 195 if (exceptionType.mayCatch(typeError()) || exceptionType.mayCatch(typeRuntimeException())) { 196 return true; 197 } 198 return false; 199 } 200 inh lazy TypeDecl TryStmt.typeError(); 201 inh lazy TypeDecl TryStmt.typeRuntimeException(); 202 203 eq IfStmt.canCompleteNormally() = (reachable() && !hasElse()) || (getThen().canCompleteNormally() || 204 (hasElse() && getElse().canCompleteNormally())); 205 eq IfStmt.getThen().reachable() = reachable(); 206 eq IfStmt.getElse().reachable() = reachable(); 207 208 209 inh boolean Stmt.reportUnreachable(); 210 eq Block.getStmt(int i).reportUnreachable() = i == 0 ? reachable() : getStmt(i-1).reachable(); 211 eq IfStmt.getThen().reportUnreachable() = reachable(); 212 eq IfStmt.getElse().reportUnreachable() = reachable(); 213 eq ForStmt.getStmt().reportUnreachable() = reachable(); 214 eq DoStmt.getStmt().reportUnreachable() = reachable(); 215 eq WhileStmt.getStmt().reportUnreachable() = reachable(); 216 eq TryStmt.getBlock().reportUnreachable() = reachable(); 217 eq TryStmt.getCatchClause().reportUnreachable() = reachable(); 218 eq TryStmt.getFinally().reportUnreachable() = reachable(); 219 eq SynchronizedStmt.getBlock().reportUnreachable() = reachable(); 220 eq SwitchStmt.getBlock().reportUnreachable() = reachable(); 221 eq TypeDecl.getChild().reportUnreachable() = true; 222 eq Program.getChild().reportUnreachable() = true; 223 224 }