import java.util.*; aspect VariableScope { inh lazy Collection TypeDecl.lookupVariable(String name); inh Collection BodyDecl.lookupVariable(String name); inh lazy Collection Block.lookupVariable(String name); inh lazy Collection SwitchStmt.lookupVariable(String name); inh lazy Collection ForStmt.lookupVariable(String name); inh Collection Expr.lookupVariable(String name); inh lazy Collection Catch.lookupVariable(String name); inh Collection VariableDeclaration.lookupVariable(String name); inh Collection ParameterDeclaration.lookupVariable(String name); protected static final Collection ASTNode.emptyVariableList = new ArrayList(0); protected static Collection ASTNode.newVariableList() { return new ArrayList(1); } eq Program.getCompilationUnit().lookupVariable(String name) = emptyVariableList; // 6.5.6.1 eq TypeDecl.getBodyDecl(int i).lookupVariable(String name) { Collection list = newVariableList(); list.addAll(findVariable(name)); if(list.isEmpty() && (isNestedType() || isAnonymous())) list.addAll(lookupVariable(name)); if(getBodyDecl(i).filterInstanceMember() || (isAnonymous() && inExplicitConstructorInvocation()) ) { for(Iterator iter = list.iterator(); iter.hasNext(); ) { Variable v = (Variable)iter.next(); if(v.isInstanceVariable()) iter.remove(); } } if(!list.isEmpty()) { return list; } return topLevelType().lookupVariable(name); // Fix to handle static imports } syn boolean BodyDecl.filterInstanceMember() = false; eq StaticInitializer.filterInstanceMember() = true; eq FieldDeclaration.filterInstanceMember() = isStatic(); eq MethodDecl.filterInstanceMember() = isStatic(); eq MemberType.filterInstanceMember() = isStatic(); eq MethodDecl.getBlock().lookupVariable(String name) = localLookupVariable(name); eq MethodDecl.getParameter().lookupVariable(String name) = localLookupVariable(name); eq ConstructorDecl.getBlock().lookupVariable(String name) = localLookupVariable(name); eq ConstructorDecl.getParameter().lookupVariable(String name) = localLookupVariable(name); eq Block.getStmt(int index).lookupVariable(String name) { Collection list = localLookupVariable(name); for(Iterator iter = list.iterator(); iter.hasNext(); ) { Variable v = (Variable)iter.next(); if(declaredBeforeUse(v, index)) { Collection result = newVariableList(); result.add(v); return result; } } return lookupVariable(name); } eq SwitchStmt.getCase(int index).lookupVariable(String name) { Collection list = localLookupVariable(name); for(Iterator iter = list.iterator(); iter.hasNext(); ) { Variable v = (Variable)iter.next(); if(declaredBeforeUse(v, index)) { Collection result = newVariableList(); result.add(v); return result; } } return lookupVariable(name); } eq ForStmt.getInitStmt().lookupVariable(String name) = localLookupVariable(name); eq ForStmt.getCondition().lookupVariable(String name) = localLookupVariable(name); eq ForStmt.getUpdateStmt().lookupVariable(String name) = localLookupVariable(name); eq ForStmt.getStmt().lookupVariable(String name) = localLookupVariable(name); eq Catch.getBlock().lookupVariable(String name) = localLookupVariable(name); eq Catch.getParameter().lookupVariable(String name) = localLookupVariable(name); eq MethodAccess.getArg().lookupVariable(String name) = unqualifiedScope().lookupVariable(name); eq ParseMethodName.getArg().lookupVariable(String name) = unqualifiedScope().lookupVariable(name); eq ConstructorAccess.getArg().lookupVariable(String name) = unqualifiedScope().lookupVariable(name); eq SuperConstructorAccess.getArg().lookupVariable(String name) = unqualifiedScope().lookupVariable(name); eq ArrayAccess.getExpr().lookupVariable(String name) = unqualifiedScope().lookupVariable(name); eq ParseArray.getDims().lookupVariable(String name) = unqualifiedScope().lookupVariable(name); eq ClassInstanceExpr.getArg().lookupVariable(String name) = unqualifiedScope().lookupVariable(name); eq AbstractDot.getRight().lookupVariable(String name) = getLeft().isPackageAccess() ? unknownType().lookupVariable(name) : getLeft().type().findVariable(name); // TODO: Check lookupVariable eq ConstructorDecl.getConstructorInvocation().lookupVariable(String name) { for(int i = 0; i < getNumParameter(); i++) { Variable v = (Variable)getParameter(i); if(v.name().equals(name)) { Collection list = newVariableList(); list.add(v); return list; } } TypeDecl hostType = hostType(); Collection list = newVariableList(); list.addAll(hostType.findVariable(name)); if(!list.isEmpty()) { removeInstanceVariables(list); } else { if(hostType.isNestedType() || hostType.isAnonymous()) { list.addAll(hostType.lookupVariable(name)); } } return list; } public void ASTNode.removeInstanceVariables(Collection c) { for(Iterator iter = c.iterator(); iter.hasNext(); ) { Variable v = (Variable)iter.next(); if(v.isInstanceVariable()) iter.remove(); } } public TypeDecl TypeDecl.subclassWithinBody(TypeDecl typeDecl) { if(instanceOf(typeDecl)) return this; if(isNestedType()) { return enclosingType().subclassWithinBody(typeDecl); } return null; } public void FieldDot.keepAccessableFields(Collection c) { TypeDecl hostType = hostType(); for(Iterator iter = c.iterator(); iter.hasNext(); ) { Variable v = (Variable)iter.next(); if(v instanceof FieldDeclaration) { FieldDeclaration f = (FieldDeclaration)v; if(!f.accessableFrom(hostType)) iter.remove(); // 6.6.2.1 else if(f.isProtected() && !f.hostPackage().equals(hostPackage()) && f.isInstanceVariable() && !getLeft().isSuperAccess()) { TypeDecl C = f.hostType(); TypeDecl S = hostType().subclassWithinBody(C); TypeDecl Q = getLeft().type(); if(S == null || !Q.instanceOf(S)) { iter.remove(); } } } else iter.remove(); } } public void FieldDot.keepClassVariables(Collection c) { for(Iterator iter = c.iterator(); iter.hasNext(); ) { Variable v = (Variable)iter.next(); if(!v.isClassVariable()) iter.remove(); } } // 15.11.1 eq FieldDot.getRight().lookupVariable(String name) { // 6.5.6.2 if(getLeft().isPackageAccess()) return unknownType().lookupVariable(name); else if(getLeft().isTypeAccess()) { Collection c = newVariableList(); c.addAll(getLeft().type().findVariable(name)); if(getLeft().type().isClassDecl()) { keepAccessableFields(c); if(c.size() == 1) keepClassVariables(c); return c; } else if(getLeft().type().isInterfaceDecl()) { keepAccessableFields(c); return c; } } else { Collection c = newVariableList(); if(getLeft().type().accessableFrom(hostType())) { c.addAll(getLeft().type().findVariable(name)); keepAccessableFields(c); } return c; } } } aspect VariableScopePropagation { interface VariableScope { public Collection lookupVariable(String name); } Catch implements VariableScope; Block implements VariableScope; TypeDecl implements VariableScope; ForStmt implements VariableScope; inh VariableScope ParameterDeclaration.outerScope(); inh VariableScope VariableDeclaration.outerScope(); eq Catch.getParameter().outerScope() = this; eq Block.getStmt().outerScope() = this; eq TypeDecl.getBodyDecl().outerScope() = this; eq ForStmt.getInitStmt().outerScope() = this; eq ForStmt.getStmt().outerScope() = this; inh Variable Access.unknownField(); inh Variable Access.illegalField(); inh Variable TypeDecl.illegalField(); syn lazy Collection VarAccess.decls() = lookupVariable(getIdUse().getID()); syn lazy Variable VarAccess.decl() { Collection decls = decls(); if(decls.size() == 1) { return (Variable)decls.iterator().next(); } return unknownField(); } } aspect LookupVariable { syn lazy Collection TypeDecl.findVariable(String name) { Collection list = newVariableList(); for(Iterator iter = fields().iterator(); iter.hasNext(); ) { FieldDeclaration decl = (FieldDeclaration)iter.next(); if(decl.getIdDecl().getID().equals(name)) { list.add(decl); } } return list; } // no lazy since needed in phases when tree has been modified syn boolean TypeDecl.hasField(String name) = findSingleVariable(name) != illegalField(); public FieldDeclaration TypeDecl.findSingleVariable(String name) { for(Iterator iter = fields().iterator(); iter.hasNext(); ) { FieldDeclaration decl = (FieldDeclaration)iter.next(); if(decl.getIdDecl().getID().equals(name)) return decl; } for(int i = 0; i < getNumBodyDecl(); i++) { if(getBodyDecl(i) instanceof FieldDeclaration) { FieldDeclaration decl = (FieldDeclaration)getBodyDecl(i); if(decl.getIdDecl().getID().equals(name)) return decl; } } return (FieldDeclaration)illegalField(); } public Collection TypeDecl.findVariable(IdDecl idDecl) { Collection list = newVariableList(); for(Iterator iter = fields().iterator(); iter.hasNext(); ) { FieldDeclaration decl = (FieldDeclaration)iter.next(); if(decl.getIdDecl().getID().equals(idDecl.getID())) list.add(decl); } return list; } syn lazy Collection TypeDecl.localLookupVariable(String name) { Collection v = findVariable(name); if(v.isEmpty()) { if(isInnerType() || isAnonymous()) { return lookupVariable(name); } else if(isNestedType() && isStatic()) { Collection w = lookupVariable(name); for(Iterator iter = w.iterator(); iter.hasNext(); ) { Variable var = (Variable)iter.next(); if(var.isStatic()) v.add(var); } } } return v; } syn lazy Collection Block.localLookupVariable(String name) { for(int i = 0; i < getNumStmt(); i++) { if(getStmt(i) instanceof Variable) { Variable v = (Variable)getStmt(i); if(v.name().equals(name)) { Collection list = newVariableList(); list.add(v); return list; } } } return emptyVariableList; } syn lazy Collection SwitchStmt.localLookupVariable(String name) { for(int i = 0; i < getNumCase(); i++) { Case c = getCase(i); for(int j = 0; j < c.getNumStmt(); j++) { if(c.getStmt(j) instanceof Variable) { Variable v = (Variable)c.getStmt(j); if(v.name().equals(name)) { Collection list = newVariableList(); list.add(v); return list; } } } } return emptyVariableList; } syn lazy Collection Catch.localLookupVariable(String name) { Variable v = (Variable)getParameter(); if(v.name().equals(name)) { Collection list = newVariableList(); list.add(v); return list; } return lookupVariable(name); } syn lazy Collection MethodDecl.localLookupVariable(String name) { for(int i = 0; i < getNumParameter(); i++) { Variable v = (Variable)getParameter(i); if(v.name().equals(name)) { Collection list = newVariableList(); list.add(v); return list; } } return lookupVariable(name); } syn lazy Collection ConstructorDecl.localLookupVariable(String name) { for(int i = 0; i < getNumParameter(); i++) { Variable v = (Variable)getParameter(i); if(v.name().equals(name)) { Collection list = newVariableList(); list.add(v); return list; } } return lookupVariable(name); } syn lazy Collection ForStmt.localLookupVariable(String name) { for(int i = 0; i < getNumInitStmt(); i++) { if(getInitStmt(i) instanceof Variable) { Variable v = (Variable)getInitStmt(i); if(v.name().equals(name)) { Collection list = newVariableList(); list.add(v); return list; } } } return lookupVariable(name); } } aspect Fields { // TODO: this somehow affects code generation of JastAdd when not lazy... syn lazy Collection TypeDecl.localFields() { Collection list = new ArrayList(); for(int i = 0; i < getNumBodyDecl(); i++) { if(getBodyDecl(i) instanceof FieldDeclaration) { FieldDeclaration decl = (FieldDeclaration)getBodyDecl(i); list.add(decl); } } return list; } syn lazy Collection TypeDecl.fields() = localFields(); eq ClassDecl.fields() { Collection list = new ArrayList(); HashSet set = new HashSet(); for(int i = 0; i < getNumImplements(); i++) { for(Iterator iter = getImplements(i).type().fields().iterator(); iter.hasNext(); ) { FieldDeclaration decl = (FieldDeclaration)iter.next(); if(!decl.isPrivate() && decl.accessableFrom(this)) set.add(decl); } } list.addAll(set); if(hasSuperClass()) { for(Iterator iter = getSuperClass().fields().iterator(); iter.hasNext(); ) { FieldDeclaration decl = (FieldDeclaration)iter.next(); if(!decl.isPrivate() && decl.accessableFrom(this) && !list.contains(decl)) list.add(decl); } } for(Iterator i2 = localFields().iterator(); i2.hasNext(); ) { FieldDeclaration decl = (FieldDeclaration)i2.next(); Set hides = hidesVariable(decl); for(Iterator iter = list.iterator(); iter.hasNext(); ) { FieldDeclaration f = (FieldDeclaration)iter.next(); if(hides.contains(f)) iter.remove(); } if(!list.contains(decl)) list.add(decl); } return list; } eq InterfaceDecl.fields() { Collection list = new ArrayList(); HashSet set = new HashSet(); for(int i = 0; i < getNumSuperInterfaceId(); i++) { for(Iterator iter = getSuperInterfaceId(i).type().fields().iterator(); iter.hasNext(); ) { FieldDeclaration f = (FieldDeclaration)iter.next(); if(f.accessableFrom(this) && !f.isPrivate()) { set.add(f); } } } list.addAll(set); for(Iterator i2 = localFields().iterator(); i2.hasNext(); ) { FieldDeclaration decl = (FieldDeclaration)i2.next(); Set hides = hidesVariable(decl); for(Iterator iter = list.iterator(); iter.hasNext(); ) { FieldDeclaration f = (FieldDeclaration)iter.next(); if(hides.contains(f)) iter.remove(); } if(!list.contains(decl)) list.add(decl); } return list; } } aspect Hides { syn lazy HashSet TypeDecl.hidesVariable(Variable v) { return new HashSet(); } eq ClassDecl.hidesVariable(Variable v) { HashSet set = new HashSet(); if(v.hostType() != this) { for(int i = 0; i < getNumBodyDecl(); i++) { if(getBodyDecl(i) instanceof FieldDeclaration) { FieldDeclaration f = (FieldDeclaration)getBodyDecl(i); if(f.name().equals(v.name())) if(f.accessableFrom(v.hostType())) set.add(f); } } } if(hasSuperClass()) { set.addAll(getSuperClass().hidesVariable(v)); } for(int i = 0; i < getNumImplements(); i++) { set.addAll(getImplements(i).type().hidesVariable(v)); } return set; } eq InterfaceDecl.hidesVariable(Variable v) { HashSet set = new HashSet(); if(v.hostType() != this) { for(int i = 0; i < getNumBodyDecl(); i++) { if(getBodyDecl(i) instanceof FieldDeclaration) { FieldDeclaration f = (FieldDeclaration)getBodyDecl(i); if(f.name().equals(v.name())) if(f.accessableFrom(v.hostType())) set.add(f); } } } for(int i = 0; i < getNumSuperInterfaceId(); i++) { set.addAll(getSuperInterfaceId(i).type().hidesVariable(v)); } return set; } }