import java.util.*; aspect TypeAnalysis { public abstract TypeUse Component.getTypeUse(); syn TypeDecl TypeUse.decl() = lookupType(getID()); inh TypeDecl TypeUse.lookupType(String name); eq Program.getChild().lookupType(String name) { for (TypeDecl td: getTypeDecls()) { if (td.getID().equals(name)) { return td; } } return null; } syn boolean TypeDecl.isAlreadyDeclared() = lookupType(getID()) != this; inh TypeDecl TypeDecl.lookupType(String name); syn TypeDecl TypeDecl.mostGeneralSuperType() { if (!hasSuper()) { return this; } else { return getSuper().decl().mostGeneralSuperType(); } } } aspect ComponentAnalysis { syn boolean Component.isTargetOfDirectedRelation() = false; eq RelationComponent.isTargetOfDirectedRelation() = isTargetOfRightDirection() | isTargetOfLeftDirection(); inh boolean RelationComponent.isTargetOfRightDirection(); eq Relation.getRight().isTargetOfRightDirection() = getDirection() instanceof RightDirection; eq Program.getChild().isTargetOfRightDirection() = false; inh boolean RelationComponent.isTargetOfLeftDirection(); eq Relation.getLeft().isTargetOfLeftDirection() = getDirection() instanceof LeftDirection; eq Program.getChild().isTargetOfLeftDirection() = false; syn String Component.name() = getID(); syn TypeDecl Component.toTypeDecl() = enclosingTypeDecl(); eq RelationComponent.toTypeDecl() = getTypeUse().decl(); inh TypeDecl Component.enclosingTypeDecl(); eq TypeDecl.getChild().enclosingTypeDecl() = this; eq Program.getChild().enclosingTypeDecl() = null; inh RelationComponent RelationComponent.otherSide(); eq Relation.getLeft().otherSide() = getRight(); eq Relation.getRight().otherSide() = getLeft(); eq Program.getChild().otherSide() = null; syn TypeDecl RelationComponent.ofTypeDecl() = otherSide().toTypeDecl(); syn boolean Component.isAlreadyDeclared() = !isTargetOfDirectedRelation() && toTypeDecl() != null && lookupComponent(toTypeDecl(), name()) != this; inh Component Component.lookupComponent(TypeDecl td, String name); eq Program.getChild().lookupComponent(TypeDecl td, String name) = lookupComponentSyn(td, name); syn Component Program.lookupComponentSyn(TypeDecl td, String name) { // Check super type first to find duplicates (shadowing is not allowed) if (td.hasSuper() && td.getSuper().decl() != null) { Component c = lookupComponentSyn(td.getSuper().decl(), name); if (c != null) return c; } for (Component c: td.getComponents()) { if (c.name().equals(name)) { return c; } } for (Relation r: getRelations()) { Component c = r.getLeft().lookup(td, name); if (c != null) return c; c = r.getRight().lookup(td, name); if (c != null) return c; } return null; } syn RelationComponent RelationComponent.lookup(TypeDecl td, String name) = !isTargetOfDirectedRelation() && toTypeDecl() == td && name().equals(name) ? this : null; coll Set TypeDecl.relationComponents() [new HashSet()] root Program; RelationComponent contributes this when !isTargetOfDirectedRelation() && toTypeDecl() != null to TypeDecl.relationComponents() for toTypeDecl(); syn Collection TypeDecl.relationComponentsTransitive() { ArrayList list = new ArrayList<>(); if (hasSuper() && getSuper().decl() != null) { list.addAll(getSuper().decl().relationComponentsTransitive()); } list.addAll(relationComponents()); return list; } syn Set TypeDecl.oneRelationComponents() { Set set = new HashSet<>(); for (RelationComponent rc: relationComponents()) { if (rc instanceof OneRelationComponent) { set.add((OneRelationComponent) rc); } } return set; } syn boolean TypeDecl.needUnresolvedClass() { // a TypeDecl needs an unresolved class, if it can appear in a relation // TODO return true; } syn boolean Component.isList() = false; eq ListComponent.isList() = true; syn boolean Component.isOpt() = false; eq OptComponent.isOpt() = true; syn boolean Component.isNullable() = false; eq TokenComponent.isNullable() = !"float double int short long char byte boolean".contains(getTypeUse().getID()); } aspect InstanceSupplier { inh Program TypeDecl.program(); eq Program.getTypeDecl(int i).program() = this; syn Collection TypeDecl.subTypeDecls() { java.util.List subDecls = new ArrayList(); for (TypeDecl decl : program().getTypeDeclList()) { if (decl.hasSuper() && decl.getSuper().getID().equals(getID())) { subDecls.add(decl); } } return subDecls; } syn TypeDecl TypeDecl.instantiableSubType() { if (getAbstract() == false) { return this; } else { for (TypeDecl sub : subTypeDecls()) { if (sub.getAbstract() == false) { return sub; } else { TypeDecl subInstance = sub.instantiableSubType(); if (subInstance != null) { return subInstance; } } } } return null; } } aspect Constructors { syn Collection TypeDecl.componentsTransitive() { ArrayList list = new ArrayList<>(); if (hasSuper() && getSuper().decl() != null) { list.addAll(getSuper().decl().componentsTransitive()); } for (Component c: getComponents()) { if (c.inConstructor()) { list.add(c); } } return list; } syn boolean TypeDecl.needsConstructor() { if (componentsTransitive().isEmpty()) { return false; } if (!relationComponents().isEmpty()) { return true; } return hasSuper() && getSuper().decl() != null && getSuper().decl().needsConstructor(); } /** * @return true, if the component should be added to the constructor (i.e., is not an NTA) */ syn boolean Component.inConstructor() = true; eq NTAComponent.inConstructor() = false; } aspect Utils { syn boolean RelationComponent.isMany() = false; eq ManyRelationComponent.isMany() = true; public String SimpleTypeUse.toString() { return getID(); } public String ParameterizedTypeUse.toString() { StringBuilder sb = new StringBuilder(); sb.append(getID()).append("<"); int i = 0; for (TypeUse u: getTypeUses()) { sb.append(u.toString()); if (++i < getNumTypeUse()) { sb.append(", "); } } sb.append(">"); return sb.toString(); } public String TypeDecl.toString() { return getID(); } }