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    }