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 UnreachableStatements { 011 012 void ASTNode.checkUnreachableStmt() { 013 } 014 void Stmt.checkUnreachableStmt() { 015 if(!reachable() && reportUnreachable()) 016 error("statement is unreachable"); 017 } 018 void StaticInitializer.checkUnreachableStmt() { 019 if(!getBlock().canCompleteNormally()) 020 error("static initializer in " + hostType().fullName() + " can not complete normally"); 021 } 022 void InstanceInitializer.checkUnreachableStmt() { 023 if(!getBlock().canCompleteNormally()) 024 error("instance initializer in " + hostType().fullName() + " can not complete normally"); 025 } 026 027 inh boolean Stmt.reachable(); 028 inh boolean Block.reachable(); 029 syn lazy boolean Stmt.canCompleteNormally() = true; 030 031 eq ConstructorDecl.getConstructorInvocation().reachable() = true; 032 eq ConstructorDecl.getBlock().reachable() = !hasConstructorInvocation() ? true : getConstructorInvocation().canCompleteNormally(); 033 eq MethodDecl.getBlock().reachable() = true; 034 eq StaticInitializer.getBlock().reachable() = true; 035 eq InstanceInitializer.getBlock().reachable() = true; 036 037 eq Block.canCompleteNormally() = getNumStmt() == 0 ? reachable() : getStmt(getNumStmt() - 1).canCompleteNormally(); 038 eq Block.getStmt().reachable() = childIndex == 0 ? reachable() : getStmt(childIndex-1).canCompleteNormally(); 039 040 eq LocalClassDeclStmt.canCompleteNormally() = reachable(); 041 042 eq VarDeclStmt.canCompleteNormally() = reachable(); 043 044 eq EmptyStmt.canCompleteNormally() = reachable(); 045 046 eq LabeledStmt.canCompleteNormally() = getStmt().canCompleteNormally() || reachableBreak(); 047 eq LabeledStmt.getStmt().reachable() = reachable(); 048 049 syn lazy boolean BranchTargetStmt.reachableBreak() { 050 for(Iterator iter = targetBreaks().iterator(); iter.hasNext(); ) { 051 BreakStmt stmt = (BreakStmt)iter.next(); 052 if(stmt.reachable()) 053 return true; 054 } 055 return false; 056 } 057 058 eq ExprStmt.canCompleteNormally() = reachable(); 059 060 syn boolean SwitchStmt.lastStmtCanCompleteNormally() = getBlock().canCompleteNormally(); 061 062 syn boolean SwitchStmt.noStmts() { 063 for(int i = 0; i < getBlock().getNumStmt(); i++) 064 if(!(getBlock().getStmt(i) instanceof Case)) 065 return false; 066 return true; 067 } 068 069 syn boolean SwitchStmt.noStmtsAfterLastLabel() = 070 getBlock().getNumStmt() > 0 && getBlock().getStmt(getBlock().getNumStmt()-1) instanceof Case; 071 072 syn boolean SwitchStmt.noDefaultLabel() { 073 for(int i = 0; i < getBlock().getNumStmt(); i++) 074 if(getBlock().getStmt(i) instanceof DefaultCase) 075 return false; 076 return true; 077 } 078 079 eq SwitchStmt.canCompleteNormally() = 080 lastStmtCanCompleteNormally() || noStmts() || noStmtsAfterLastLabel() || noDefaultLabel() || reachableBreak(); 081 082 eq SwitchStmt.getBlock().reachable() = reachable(); 083 syn boolean Case.reachable() = getParent().getParent() instanceof Block && ((Block)getParent().getParent()).reachable(); 084 085 eq WhileStmt.canCompleteNormally() = reachable() && (!getCondition().isConstant() || !getCondition().isTrue()) || reachableBreak(); 086 eq WhileStmt.getStmt().reachable() = reachable() && !getCondition().isFalse(); 087 088 eq DoStmt.canCompleteNormally() = getStmt().canCompleteNormally() && (!getCondition().isConstant() || !getCondition().isTrue()) 089 || reachableContinue() && (!getCondition().isConstant() || !getCondition().isTrue()) || reachableBreak(); 090 091 syn lazy boolean BranchTargetStmt.reachableContinue() { 092 for(Iterator iter = targetContinues().iterator(); iter.hasNext(); ) { 093 Stmt stmt = (Stmt)iter.next(); 094 if(stmt.reachable()) 095 return true; 096 } 097 return false; 098 } 099 100 eq DoStmt.getStmt().reachable() = reachable(); 101 102 eq ForStmt.canCompleteNormally() = reachable() && hasCondition() && (!getCondition().isConstant() || !getCondition().isTrue()) || reachableBreak(); 103 eq ForStmt.getStmt().reachable() = reachable() && (!hasCondition() || (!getCondition().isConstant() || !getCondition().isFalse())); 104 105 eq BreakStmt.canCompleteNormally() = false; 106 eq ContinueStmt.canCompleteNormally() = false; 107 eq ReturnStmt.canCompleteNormally() = false; 108 eq ThrowStmt.canCompleteNormally() = false; 109 110 eq SynchronizedStmt.canCompleteNormally() = getBlock().canCompleteNormally(); 111 eq SynchronizedStmt.getBlock().reachable() = reachable(); 112 113 eq TryStmt.canCompleteNormally() { 114 boolean anyCatchClauseCompleteNormally = false; 115 for(int i = 0; i < getNumCatchClause() && !anyCatchClauseCompleteNormally; i++) 116 anyCatchClauseCompleteNormally = getCatchClause(i).getBlock().canCompleteNormally(); 117 return (getBlock().canCompleteNormally() || anyCatchClauseCompleteNormally) && 118 (!hasFinally() || getFinally().canCompleteNormally()); 119 } 120 eq TryStmt.getBlock().reachable() = reachable(); 121 eq TryStmt.getFinally().reachable() = reachable(); 122 eq BasicCatch.getBlock().reachable() = reachableCatchClause(getParameter().type()); 123 124 /** 125 * @return true if an exception of type exceptionType is catchable by the catch clause 126 */ 127 inh lazy boolean CatchClause.reachableCatchClause(TypeDecl exceptionType); 128 eq TryStmt.getCatchClause(int childIndex).reachableCatchClause(TypeDecl exceptionType) { 129 for(int i = 0; i < childIndex; i++) 130 if(getCatchClause(i).handles(exceptionType)) 131 return false; 132 if(catchableException(exceptionType)) 133 return true; 134 if(exceptionType.mayCatch(typeError()) || exceptionType.mayCatch(typeRuntimeException())) 135 return true; 136 return false; 137 } 138 inh lazy TypeDecl TryStmt.typeError(); 139 inh lazy TypeDecl TryStmt.typeRuntimeException(); 140 141 eq IfStmt.canCompleteNormally() = (reachable() && !hasElse()) || (getThen().canCompleteNormally() || 142 (hasElse() && getElse().canCompleteNormally())); 143 eq IfStmt.getThen().reachable() = reachable(); 144 eq IfStmt.getElse().reachable() = reachable(); 145 146 147 inh boolean Stmt.reportUnreachable(); 148 eq Block.getStmt(int i).reportUnreachable() = i == 0 ? reachable() : getStmt(i-1).reachable(); 149 eq IfStmt.getThen().reportUnreachable() = reachable(); 150 eq IfStmt.getElse().reportUnreachable() = reachable(); 151 eq ForStmt.getStmt().reportUnreachable() = reachable(); 152 eq DoStmt.getStmt().reportUnreachable() = reachable(); 153 eq WhileStmt.getStmt().reportUnreachable() = reachable(); 154 eq TryStmt.getBlock().reportUnreachable() = reachable(); 155 eq TryStmt.getCatchClause().reportUnreachable() = reachable(); 156 eq TryStmt.getFinally().reportUnreachable() = reachable(); 157 eq SynchronizedStmt.getBlock().reportUnreachable() = reachable(); 158 eq SwitchStmt.getBlock().reportUnreachable() = reachable(); 159 eq TypeDecl.getChild().reportUnreachable() = true; 160 // ES: switching to getChild to include compilation units moved to NTAs 161 //eq Program.getCompilationUnit().reportUnreachable() = true; 162 eq Program.getChild().reportUnreachable() = true; 163 164 }