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    }