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 }