import java.util.*; aspect TypeName { syn String TypeDecl.name() = getIdDecl().getID(); syn lazy String TypeDecl.fullName() { String packageName = packageName(); if(packageName.equals("")) return name(); return packageName + "." + name(); } inh lazy String TypeDecl.packageName(); eq CompilationUnit.getTypeDecl().packageName() = packageName(); eq CompilationUnit.getImportDecl().packageName() = packageName(); eq TypeDecl.getBodyDecl().packageName() = packageName().equals("") ? name() : packageName() + "." + name(); syn lazy String CompilationUnit.packageName() { StringBuffer s = new StringBuffer(); for(int i = 0; i < getNumPackageDecl(); i++) { s.append(getPackageDecl(i).getID()); if(i + 1 < getNumPackageDecl()) s.append("."); } return s.toString(); } } aspect SuperClasses { syn lazy boolean PrimitiveType.hasSuperClass() { return hasSuperClassAccess(); } syn lazy TypeDecl PrimitiveType.getSuperClass() { return getSuperClassAccess().type(); } syn lazy boolean ClassDecl.hasSuperClass() { return hasSuperClassAccess() && !isObject(); } syn lazy TypeDecl ClassDecl.getSuperClass() { return getSuperClassAccess().type(); } rewrite ClassDecl { when(!hasSuperClassAccess() && !isObject()) to ClassDecl { setSuperClassAccess( new TypeAccess( new List().add(new IdUse("java")).add(new IdUse("lang")), new IdUse("Object") ) ); return this; } when(isObject() && (hasSuperClassAccess() || getNumImplements() != 0)) to ClassDecl { setSuperClassAccessOpt(new Opt()); setImplementsList(new List()); return this; } } rewrite InterfaceDecl { when(getNumSuperInterfaceId() == 0) to InterfaceDecl { addSuperInterfaceId( new TypeAccess( new List().add(new IdUse("java")).add(new IdUse("lang")), new IdUse("Object") ) ); return this; } } } aspect Circularity { inh lazy TypeDecl TypeDecl.illegalType(); syn lazy boolean TypeDecl.isCircular() = false; /* syn lazy boolean TypeDecl.isCircular() circular [true] = false; eq ClassDecl.isCircular() { return hasSuperClass() && getSuperClass().isCircular(); } eq InterfaceDecl.isCircular() { for(int i = 0; i < getNumSuperInterfaceId(); i++) { TypeDecl typeDecl = getSuperInterfaceId(i).type(); if(typeDecl.isCircular()) return true; } return false; } */ rewrite ClassDecl { when(!duringResolveAmbiguousNames() && isCircular()) to ClassDecl { setSuperClassAccess( new TypeAccess( new List().add(new IdUse("primitive")), new IdUse("Illegal") ) ); return this; } } rewrite InterfaceDecl { when(!duringResolveAmbiguousNames() && checkAndRewriteSuperInterfaces()) to InterfaceDecl this; } private boolean InterfaceDecl.checkAndRewriteSuperInterfaces() { boolean rewritten = false; for(int i = 0; i < getNumSuperInterfaceId(); i++) { TypeDecl typeDecl = getSuperInterfaceId(i).type(); if(typeDecl.isCircular()) { setSuperInterfaceId(illegalType().createQualifiedAccess(), i); rewritten = true; } } return rewritten; } } aspect ImplicitConstructor { rewrite ClassDecl { when(noConstructor()) to ClassDecl { Modifiers m = new Modifiers(); if(isPublic()) m.addModifier(new Modifier("public")); if(isProtected()) m.addModifier(new Modifier("protected")); if(isPrivate()) m.addModifier(new Modifier("private")); addBodyDecl( new ConstructorDecl( m, new IdDecl(name()), new List(), new List(), new Opt(), new Block() ) ); return this; } } syn lazy boolean ClassDecl.noConstructor() { //for(int i = getNumBodyDecl()-1; i >= 0; i--) // Does not work since rewrite adds a list of nodes to the current position. Should use iterators instead for(int i = 0; i < getNumBodyDecl(); i++) if(getBodyDecl(i) instanceof ConstructorDecl) return false; return true; } // 8.8.5 rewrite ConstructorDecl { when(!hasConstructorInvocation() && !hostType().isObject()) to ConstructorDecl { setConstructorInvocation( new ExprStmt( new SuperConstructorAccess(new List(), new IdUse("super")) ) ); return this; } } } aspect AnonymousClasses { inh TypeDecl AnonymousDecl.superType(); eq ClassInstanceExpr.getTypeDecl().superType() = getAccess().type(); eq Program.getCompilationUnit().superType() = null; inh ConstructorDecl AnonymousDecl.constructorDecl(); eq ClassInstanceExpr.getTypeDecl().constructorDecl() { ArrayList list = getAccess().type().lookupConstructor(this); if(list.size() == 1) return (ConstructorDecl)list.get(0); return illegalConstructor(); } eq Program.getCompilationUnit().constructorDecl() = null; public Access TypeDecl.createQualifiedAccess() { if(isLocalClass() || isAnonymous()) { return new TypeAccess(new List(), new IdUse(name())); } else if(!isTopLevelType()) { return new TypeDot(enclosingType().createQualifiedAccess(), new TypeAccess(new List(), new IdUse(name()))); } else { String[] strings = fullName().split("\\."); List list = new List(); for(int i = 0; i < strings.length - 1; i++) list.add(new IdUse(strings[i])); return new TypeAccess(list, new IdUse(strings[strings.length-1])); } } public Access PrimitiveType.createQualifiedAccess() { return new TypeAccess(new List(), new IdUse(name())); } protected static int ASTNode.anonymousIndex = 0; syn lazy Opt AnonymousDecl.getSuperClassAccessOpt() { if(superType().isInterfaceDecl()) return new Opt(typeObject().createQualifiedAccess()); else return new Opt(superType().createQualifiedAccess()); } syn lazy List AnonymousDecl.getImplementsList() { if(superType().isInterfaceDecl()) return new List().add(superType().createQualifiedAccess()); else return new List(); } rewrite AnonymousDecl { //when(!duringResolveAmbiguousNames() && !duringVariableDeclaration() && !duringHelper() && noConstructor()) when(noConstructor()) to AnonymousDecl { setModifiers(new Modifiers(new List().add(new Modifier("final")))); ConstructorDecl constructor = (ConstructorDecl)constructorDecl().fullCopy(); addBodyDecl(constructor); getIdDecl().setID("Anonymous" + anonymousIndex++); constructor.setIdDecl((IdDecl)getIdDecl().fullCopy()); List argList = new List(); for(int i = 0; i < constructor.getNumParameter(); i++) argList.add(new VarAccess(new IdUse(constructor.getParameter(i).getIdDecl().getID()))); constructor.setConstructorInvocation( new ExprStmt( new SuperConstructorAccess( argList, new IdUse("super") ) ) ); constructor.setBlock(new Block()); Set set = new HashSet(); for(int i = 0; i < getNumBodyDecl(); i++) { if(getBodyDecl(i) instanceof InstanceInitializer) { InstanceInitializer init = (InstanceInitializer)getBodyDecl(i); set.addAll(init.exceptions()); } else if(getBodyDecl(i) instanceof FieldDeclaration) { FieldDeclaration f = (FieldDeclaration)getBodyDecl(i); if(f.isInstanceVariable()) { //System.err.println(f.name() + " in anonymous class " + fullName() + " may throw exceptions"); set.addAll(f.exceptions()); } } } List exceptionList = new List(); for(Iterator iter = set.iterator(); iter.hasNext(); ) { TypeDecl exceptionType = (TypeDecl)iter.next(); if(exceptionType.isNull()) exceptionType = typeNullPointerException(); exceptionList.add(exceptionType.createQualifiedAccess()); } constructor.setExceptionList(exceptionList); return this; } } inh TypeDecl AnonymousDecl.typeNullPointerException(); }