aspect With { public WithStmt.WithStmt(Access acc, Block block) { this(new List().add(acc), block); } // pretty printing public void WithStmt.toString(StringBuffer s) { s.append(indent()); s.append("with("); for(int i=0;i=0;--i) { TypeDecl td = getQualifier(i).type(); SimpleSet c = td.memberFields(name); if(td.inStaticContext() || td.isStatic()) c = removeInstanceVariables(c); if(!c.isEmpty()) return c; } return removeFields(lookupVariable(name)); } public SimpleSet ASTNode.removeFields(SimpleSet s) { SimpleSet res = SimpleSet.emptySet; for(Iterator iter=s.iterator();iter.hasNext();) { Variable v = (Variable)iter.next(); if(!v.isInstanceVariable() && !v.isClassVariable()) res = res.add(v); } return res; } // TODO: accessVariable, accessMethod eq WithStmt.getStmt().lookupMethod(String name) { for(int i=getNumQualifier()-1;i>=0;--i) { TypeDecl td = getQualifier(i).type(); Collection c = td.memberMethods(name); if(!c.isEmpty()) return c; } return Collections.EMPTY_LIST; } eq WithStmt.getStmt().lookupType(String name) { for(int i=getNumQualifier()-1;i>=0;--i) { SimpleSet c = getQualifier(i).qualifiedLookupType(name); if(!c.isEmpty()) return c; } // TODO: filter out non-static ones? return lookupType(name); } // control flow eq WithStmt.succ() = getNumQualifier() == 0 ? SmallSet.singleton(getStmt()) : SmallSet.singleton(getQualifier(0).first()); eq WithStmt.getQualifier(int i).following() = i+1 < getNumQualifier() ? SmallSet.singleton(getQualifier(i+1).first()) : SmallSet.singleton(getStmt()); eq WithStmt.getStmt().following() = following(); // eliminating with statements public static LanguageExtension ASTNode.WITH_STMT = new LanguageExtension("with statement") { public void eliminateOn(ASTNode n) { n.eliminateWith(); n.flushCaches(); } }; public ASTNode ASTNode.eliminateWith() { for(int i=0;i qualifiers, TypeDecl hostType) { for(int i=0;i qualifiers, TypeDecl hostType) { qualifiers.add(this.createLockedAccess().qualifiesAccess(new ThisAccess(true))); super.eliminateWith(qualifiers, hostType); qualifiers.removeChild(qualifiers.getNumChild()-1); } // "this" accesses are replaced with a copy of the corresponding qualifier // "super" accesses are replaced with casted copies of a qualifier // super method calls are handled differently: they are only replaced if the qualifier // is itself a "this" access (otherwise semantics would change) public void Expr.eliminateWith(List qualifiers, TypeDecl hostType) { if(isThisAccess()) { for(int i=qualifiers.getNumChild()-1;i>=0;--i) { Access qual = qualifiers.getChild(i); TypeDecl qual_type = qual.type().isParameterizedType() ? ((ParTypeDecl)qual.type()).genericDecl() : qual.type(); if(qual_type.subtype(this.type())) { if(qual.isThisAccess() && qual_type == this.type()) return; if(isLeftChildOfDot()) replace(getParent()).with(((Expr)qual.fullCopyAndDetach()).qualifiesAccess(parentDot().getRight())); else replaceWith(qual.fullCopyAndDetach()); return; } } throw new RefactoringException("cannot eliminate this"); } else if(isSuperAccess()) { for(int i=qualifiers.getNumChild()-1;i>=0;--i) { Access qual = qualifiers.getChild(i); TypeDecl qual_type = qual.type().isParameterizedType() ? ((ParTypeDecl)qual.type()).genericDecl() : qual.type(); if(!qual_type.isClassDecl() || !((ClassDecl)qual_type).hasSuperclass()) continue; ClassDecl cd = (ClassDecl)qual_type; if(this.type().equals(cd.superclass())) { if(((Access)this).qualifiesMethodAccess()) { if(qual.isThisAccess()) { Access qual_super = (Access)qual.convertThisToSuper(); if(qual_super != null) { if(isLeftChildOfDot()) replace(getParent()).with(qual_super.qualifiesAccess(parentDot().getRight())); return; } } throw new RefactoringException("cannot eliminate with on super method calls"); } else { replaceWith(new ParExpr(new CastExpr(cd.superclass().createLockedAccess(), (Expr)qual.fullCopyAndDetach()))); } return; } } throw new RefactoringException("cannot eliminate super"); } else { super.eliminateWith(qualifiers, hostType); } } public void AbstractDot.eliminateWith(List qualifiers, TypeDecl hostType) { rotateLeft(); if(isThisAccess() || isSuperAccess()) { super.eliminateWith(qualifiers, hostType); } else { getRight().eliminateWith(qualifiers, hostType); getLeft().eliminateWith(qualifiers, hostType); } } // qualify unqualified method accesses public void MethodAccess.eliminateWith(List qualifiers, TypeDecl hostType) { if(isQualified()) { super.eliminateWith(qualifiers, hostType); } else { for(int i=qualifiers.getNumChild()-1;i>=0;i--) { Access qual = qualifiers.getChild(i); Collection meths = qual.type().memberMethods(name()); if(meths.contains(decl())) { lock(); qualifyWith((Expr)qual.fullCopyAndDetach()); flushCaches(); super.eliminateWith(qualifiers, hostType); return; } } throw new RefactoringException("cannot eliminate with"); } } // qualify unqualified "new" expressions public void ClassInstanceExpr.eliminateWith(List qualifiers, TypeDecl hostType) { TypeDecl td = getAccess().type(); if(!isQualified() && td.isMemberType() && !td.isStatic()) { for(int i=qualifiers.getNumChild()-1;i>=0;i--) { Access qual = qualifiers.getChild(i); TypeDecl qual_type = qual.type().isParameterizedType() ? ((ParTypeDecl)qual.type()).genericDecl() : qual.type(); if(qual_type.subtype(td.enclosingType())) { if(!getAccess().type().accessibleFrom(hostType)) throw new RefactoringException("type not accessible"); qualifyWith((Expr)qual.fullCopyAndDetach()); flushCaches(); super.eliminateWith(qualifiers, hostType); return; } } throw new RefactoringException("cannot eliminate with"); } super.eliminateWith(qualifiers, hostType); } // qualify unqualified field accesses public void VarAccess.eliminateWith(List qualifiers, TypeDecl hostType) { enclosingBodyDecl().flushCaches(); if(!isQualified() && decl() instanceof FieldDeclaration && !decl().isStatic()) { for(int i=qualifiers.getNumChild()-1;i>=0;i--) { Access qual = qualifiers.getChild(i); if(qual.type().subtype(decl().hostType())) { if(!((FieldDeclaration)decl()).accessibleFrom(hostType)) throw new RefactoringException("field not accessible"); qualifyWith((Expr)qual.fullCopyAndDetach()); flushCaches(); super.eliminateWith(qualifiers, hostType); return; } } throw new RefactoringException("cannot eliminate with"); } super.eliminateWith(qualifiers, hostType); } syn lazy boolean Access.qualifiesMethodAccess() = hasParentDot() && parentDot().isMethodAccess(); }