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    import java.util.Collection;
011    import java.util.ArrayList;
012    
013    aspect EnhancedFor {
014      // type checking
015        public void EnhancedForStmt.typeCheck() {
016                if (!getExpr().type().isArrayDecl() && !getExpr().type().isIterable()) {
017                        error("type " + getExpr().type().name() + 
018                              " of expression in foreach is neither array type nor java.lang.Iterable");
019                }       
020        else if(getExpr().type().isArrayDecl() && !getExpr().type().componentType().assignConversionTo(getVariableDeclaration().type(), null))
021          error("parameter of type " + getVariableDeclaration().type().typeName() + " can not be assigned an element of type " + getExpr().type().componentType().typeName()); 
022        else if(getExpr().type().isIterable() && !getExpr().type().isUnknown()) {
023          MethodDecl iterator = (MethodDecl)getExpr().type().memberMethods("iterator").iterator().next();
024          MethodDecl next = (MethodDecl)iterator.type().memberMethods("next").iterator().next();
025          TypeDecl componentType = next.type();
026          if(!componentType.assignConversionTo(getVariableDeclaration().type(), null))
027            error("parameter of type " + getVariableDeclaration().type().typeName() + " can not be assigned an element of type " + componentType.typeName()); 
028        }
029        }
030      
031        /**
032         * True if type is java.lang.Iterable or subtype
033           As long as we use the 1.4 API we check for java.util.Collection instead.
034         */
035        syn lazy boolean TypeDecl.isIterable() = instanceOf(lookupType("java.lang", "Iterable"));
036      
037        // variable lookup
038      inh SimpleSet EnhancedForStmt.lookupVariable(String name);
039        eq EnhancedForStmt.getVariableDeclaration().lookupVariable(String name) = localLookupVariable(name);
040        eq EnhancedForStmt.getExpr().lookupVariable(String name) = localLookupVariable(name);
041        eq EnhancedForStmt.getStmt().lookupVariable(String name) = localLookupVariable(name);
042    
043      eq EnhancedForStmt.getVariableDeclaration().nameType() = NameType.TYPE_NAME;
044      
045      EnhancedForStmt implements VariableScope;
046      eq EnhancedForStmt.getVariableDeclaration().outerScope() = this;
047      eq EnhancedForStmt.getExpr().outerScope() = this;
048      eq EnhancedForStmt.getStmt().outerScope() = this;
049    
050        syn SimpleSet EnhancedForStmt.localLookupVariable(String name) {
051                if(getVariableDeclaration().name().equals(name)) {
052          return SimpleSet.emptySet.add(getVariableDeclaration());
053        }
054          return lookupVariable(name);
055        }
056      
057        // pretty printing
058      public void EnhancedForStmt.toString(StringBuffer s) {
059        s.append(indent());
060        s.append("for (");
061        getVariableDeclaration().getModifiers().toString(s);
062        getVariableDeclaration().getTypeAccess().toString(s);
063        s.append(" " + getVariableDeclaration().name());
064        s.append(" : ");
065        getExpr().toString(s);
066        s.append(") ");
067        getStmt().toString(s);
068      } 
069      
070        // some attributes for the parameter
071        eq EnhancedForStmt.getVariableDeclaration().isMethodParameter() = false;
072        eq EnhancedForStmt.getVariableDeclaration().isConstructorParameter() = false;
073        eq EnhancedForStmt.getVariableDeclaration().isExceptionHandlerParameter() = false;
074    
075      eq EnhancedForStmt.targetOf(ContinueStmt stmt) = !stmt.hasLabel();
076      eq EnhancedForStmt.targetOf(BreakStmt stmt) = !stmt.hasLabel();
077    
078      // Unreachable Statements
079      eq EnhancedForStmt.canCompleteNormally() = reachable();
080      eq EnhancedForStmt.getStmt().reachable() = reachable();
081    
082      // Definite Assignment
083      eq EnhancedForStmt.isDAafter(Variable v) {
084        if(!getExpr().isDAafter(v))
085          return false;
086        /*
087        for(Iterator iter = targetBreaks().iterator(); iter.hasNext(); ) {
088          BreakStmt stmt = (BreakStmt)iter.next();
089          if(!stmt.isDAafterReachedFinallyBlocks(v))
090            return false;
091        }
092        */
093        return true;
094      }
095      eq EnhancedForStmt.getExpr().isDAbefore(Variable v) = 
096        v == getVariableDeclaration() || isDAbefore(v);
097      eq EnhancedForStmt.getStmt().isDAbefore(Variable v) = getExpr().isDAafter(v);
098    
099      eq EnhancedForStmt.isDUafter(Variable v) {
100        if(!getExpr().isDUafter(v))
101          return false;
102        for(Iterator iter = targetBreaks().iterator(); iter.hasNext(); ) {
103          BreakStmt stmt = (BreakStmt)iter.next();
104          if(!stmt.isDUafterReachedFinallyBlocks(v))
105            return false;
106        }
107        return true;
108      }
109      eq EnhancedForStmt.getExpr().isDUbefore(Variable v) = 
110        v != getVariableDeclaration() && isDUbefore(v);
111      eq EnhancedForStmt.getStmt().isDUbefore(Variable v) = getExpr().isDUafter(v);
112    
113      eq EnhancedForStmt.getStmt().insideLoop() = true;
114      eq EnhancedForStmt.continueLabel() = true;
115    
116    }