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    import java.util.Collection;
032    import java.util.ArrayList;
033    
034    aspect EnhancedFor {
035    
036      // branch propagation
037      eq EnhancedForStmt.getChild().branchTarget(Stmt branch) =
038          branch.canBranchTo(this) ? this : branchTarget(branch);
039    
040      // type checking
041      public void EnhancedForStmt.typeCheck() {
042        if (!getExpr().type().isArrayDecl() && !getExpr().type().isIterable()) {
043          errorf("type %s of expression in foreach is neither array type nor java.lang.Iterable",
044              getExpr().type().name());
045        } else if (getExpr().type().isArrayDecl() && !getExpr().type().componentType().assignConversionTo(getVariableDeclaration().type(), null)) {
046          errorf("parameter of type %s can not be assigned an element of type %s",
047              getVariableDeclaration().type().typeName(), getExpr().type().componentType().typeName());
048        } else if (getExpr().type().isIterable() && !getExpr().type().isUnknown()) {
049          MethodDecl iterator = (MethodDecl) getExpr().type().memberMethods("iterator").iterator().next();
050          MethodDecl next = (MethodDecl) iterator.type().memberMethods("next").iterator().next();
051          TypeDecl componentType = next.type();
052          if (!componentType.assignConversionTo(getVariableDeclaration().type(), null)) {
053            errorf("parameter of type %s can not be assigned an element of type %s",
054                getVariableDeclaration().type().typeName(), componentType.typeName());
055          }
056        }
057      }
058    
059      /**
060       * True if type is java.lang.Iterable or subtype
061         As long as we use the 1.4 API we check for java.util.Collection instead.
062       */
063      syn lazy boolean TypeDecl.isIterable() = instanceOf(lookupType("java.lang", "Iterable"));
064    
065      // variable lookup
066      inh SimpleSet EnhancedForStmt.lookupVariable(String name);
067      eq EnhancedForStmt.getVariableDeclaration().lookupVariable(String name) = localLookupVariable(name);
068      eq EnhancedForStmt.getExpr().lookupVariable(String name) = localLookupVariable(name);
069      eq EnhancedForStmt.getStmt().lookupVariable(String name) = localLookupVariable(name);
070    
071      eq EnhancedForStmt.getVariableDeclaration().nameType() = NameType.TYPE_NAME;
072    
073      EnhancedForStmt implements VariableScope;
074      eq EnhancedForStmt.getVariableDeclaration().outerScope() = this;
075      eq EnhancedForStmt.getExpr().outerScope() = this;
076      eq EnhancedForStmt.getStmt().outerScope() = this;
077    
078      syn SimpleSet EnhancedForStmt.localLookupVariable(String name) {
079        if (getVariableDeclaration().name().equals(name)) {
080          return SimpleSet.emptySet.add(getVariableDeclaration());
081        }
082        return lookupVariable(name);
083      }
084    
085      // Pretty printing.
086      public void EnhancedForStmt.prettyPrint(PrettyPrinter out) {
087        out.print("for (");
088        out.print(getVariableDeclaration().getModifiers());
089        out.print(getVariableDeclaration().getTypeAccess());
090        out.print(" " + getVariableDeclaration().name());
091        out.print(" : ");
092        out.print(getExpr());
093        out.print(") ");
094        if (getStmt() instanceof Block) {
095          out.print(getStmt());
096        } else {
097          out.print("{");
098          out.println();
099          out.indent(1);
100          out.print(getStmt());
101          out.println();
102          out.print("}");
103        }
104      }
105    
106      // some attributes for the parameter
107      eq EnhancedForStmt.getVariableDeclaration().isMethodParameter() = false;
108      eq EnhancedForStmt.getVariableDeclaration().isConstructorParameter() = false;
109      eq EnhancedForStmt.getVariableDeclaration().isExceptionHandlerParameter() = false;
110    
111      // Unreachable Statements
112      eq EnhancedForStmt.canCompleteNormally() = reachable();
113      eq EnhancedForStmt.getStmt().reachable() = reachable();
114    
115      // Definite Assignment
116      eq EnhancedForStmt.isDAafter(Variable v) {
117        if (!getExpr().isDAafter(v)) {
118          return false;
119        }
120        /*
121        for (Iterator iter = targetBreaks().iterator(); iter.hasNext(); ) {
122          BreakStmt stmt = (BreakStmt) iter.next();
123          if (!stmt.isDAafterReachedFinallyBlocks(v)) {
124            return false;
125          }
126        }
127        */
128        return true;
129      }
130      eq EnhancedForStmt.getExpr().isDAbefore(Variable v) =
131          v == getVariableDeclaration() || isDAbefore(v);
132      eq EnhancedForStmt.getStmt().isDAbefore(Variable v) = getExpr().isDAafter(v);
133    
134      eq EnhancedForStmt.isDUafter(Variable v) {
135        if (!getExpr().isDUafter(v)) {
136          return false;
137        }
138        for (Iterator iter = targetBreaks().iterator(); iter.hasNext(); ) {
139          BreakStmt stmt = (BreakStmt) iter.next();
140          if (!stmt.isDUafterReachedFinallyBlocks(v)) {
141            return false;
142          }
143        }
144        return true;
145      }
146      eq EnhancedForStmt.getExpr().isDUbefore(Variable v) =
147          v != getVariableDeclaration() && isDUbefore(v);
148      eq EnhancedForStmt.getStmt().isDUbefore(Variable v) = getExpr().isDUafter(v);
149    
150      eq EnhancedForStmt.getStmt().insideLoop() = true;
151      eq EnhancedForStmt.continueLabel() = true;
152    
153    }