aspect NameCheck { public void ASTNode.nameCheck() { } public TypeDecl ASTNode.extractSingleType(TypeCollection c) { if(c.size() != 1) return null; return c.first(); } public void SingleTypeImportDecl.nameCheck() { if(!getAccess().type().fullName().equals(fullName())) error("Single-type import " + fullName() + " is not the canonical name of type " + getAccess().type().fullName()); //CompilationUnit cu = (CompilationUnit)getParent().getParent(); // FIXME //if(getAccess().type() != extractSingleType(cu.lookupType(getAccess().type().name()))) // error("Importing the same type " + getAccess().type().name() + " twice is illegal"); } public void CompilationUnit.nameCheck() { for(int i = 0; i < getNumImportDecl(); i++) { ImportDecl decl = getImportDecl(i); if(decl instanceof SingleTypeImportDecl) { if(!localLookupType(decl.getAccess().type().name()).contains(decl.getAccess().type())) error("" + decl + " is conflicting with visible type"); } } } public void PackageAccess.nameCheck() { if(!hasPackage(packageName())) { error("package " + packageName() + " does not exist but is used in " + enclosingStmt()); } } inh String MethodAccess.methodHost(); eq TypeDecl.getBodyDecl().methodHost() = fullName(); eq AbstractDot.getRight().methodHost() = getLeft().type().fullName(); eq Program.getCompilationUnit().methodHost() { throw new Error("Needs extra equation for methodHost()"); } public void MethodAccess.nameCheck() { if(decl() == unknownMethod() && decls().size() <= 1) { StringBuffer s = new StringBuffer(); s.append("no method named " + getIdUse().getID()); s.append("("); for(int i = 0; i < getNumArg(); i++) { if(i != 0) s.append(", "); s.append(getArg(i).type().fullName()); } //s.append(")" + " in " + hostType().fullName() + " matches " + this); s.append(")" + " in " + methodHost() + " matches " + this); error(s.toString()); } if(decls().size() > 1) { boolean allAbstract = true; for(MethodCollection.MethodIterator iter = decls().iterator(); iter.hasNext() && allAbstract; ) { if(!((MethodDecl)iter.next()).isAbstract()) allAbstract = false; } if(!allAbstract) { StringBuffer s = new StringBuffer(); s.append("several most specific methods for " + this + "\n"); for(MethodCollection.MethodIterator iter = decls().iterator(); iter.hasNext(); ) { MethodDecl m = (MethodDecl)iter.next(); s.append(" " + m.signature() + " in " + m.hostType().fullName() + "\n"); } error(s.toString()); } } // 8.8.5.1 /* if(!decl().isStatic() && inExplicitConstructorInvocation() && !isQualified() && hostType().instanceOf(decl().hostType())) error("instance method " + decl().signature() + " may not be accessed in an explicit constructor invocation"); */ /* if(!decl().isStatic() && inStaticContext()) error("instance method " + decl().signature() + " may not be accessed in a static context"); */ // 8.5.2 /* if(!isQualified() && !decl().isStatic() && hostType().isClassDecl() && !hostType().isInnerTypeOf(decl().hostType()) && !hostType().methods().contains(decl())) { StringBuffer s = new StringBuffer(); s.append("a static class must not acccess non-static method of the enclosing class"); s.append(", illegal access to " + decl().signature() + " in " + decl().hostType().fullName() + " from " + hostType().fullName()); error(s.toString()); }*/ } public void ConstructorDecl.nameCheck() { super.nameCheck(); // 8.8 if(!hostType().name().equals(getIdDecl().getID())) error("constructor " + getIdDecl().getID() +" does not have the same name as the simple name of the host class " + hostType().name()); // 8.8.2 if(hostType().lookupConstructor(this) != this) error("constructor with signature " + signature() + " is multiply declared in type " + hostType().fullName()); if(circularThisInvocation(this)) error("The constructor " + signature() + " may not directly or indirectly invoke itself"); } // 8.8.5 syn boolean ConstructorDecl.circularThisInvocation(ConstructorDecl decl) { if(hasConstructorInvocation()) { Expr e = ((ExprStmt)getConstructorInvocation()).getExpr(); if(e instanceof ConstructorAccess) { ConstructorDecl constructorDecl = ((ConstructorAccess)e).decl(); if(constructorDecl == decl) return true; return constructorDecl.circularThisInvocation(decl); } } return false; } public void MethodDecl.nameCheck() { // 8.4 // 8.4.2 if(!hostType().localLookupMethod(this).contains(this)) error("method with signature " + signature() + " is multiply declared in type " + hostType().fullName()); // 8.4.3.4 if(isNative() && hasBlock()) error("native methods must have an empty semicolon body"); // 8.4.5 if(isAbstract() && hasBlock()) error("abstract methods must have an empty semicolon body"); // 8.4.5 if(!hasBlock() && !(isNative() || isAbstract())) error("only abstract and native methods may have an empty semicolon body"); // 8.4.5 if(!isVoid() && hasBlock() && getBlock().canCompleteNormally()) error("the body of a non void method may not complete normally"); } syn boolean Expr.staticContext() = false; eq TypeAccess.staticContext() = true; eq ThisAccess.staticContext() = false; eq SuperAccess.staticContext() = false; eq AbstractDot.staticContext() = getRight().staticContext(); syn VarAccess FieldDot.fieldAccess() = (VarAccess)getRight(); syn FieldDeclaration FieldDot.decl() = (FieldDeclaration)fieldAccess().decl(); public void FieldDot.nameCheck() { /* if(getLeft().staticContext() && !decl().isStatic()) error("The field " + decl() + " is not static, and cannot be accessed in this static context."); */ } public void MethodDot.nameCheck() { /* if(getLeft().staticContext() && !decl().isStatic()) error("The method " + decl().signature() + " is not static, and cannot be accessed in this static context."); */ if(getLeft() instanceof PackageAccess || getLeft() instanceof PackageDot) error("The method " + decl().signature() + " can not be qualified by a package name."); if(getLeft().isSuperAccess() && decl().isAbstract()) error("Invoking an abstract method thorugh super.method() is invalid"); } syn MethodAccess MethodDot.methodAccess() = (MethodAccess)getRight(); syn MethodDecl MethodDot.decl() = methodAccess().decl(); public void ConstructorAccess.nameCheck() { super.nameCheck(); if(decl() == illegalConstructor() && decls().size() <= 1) error("no constructor named " + getIdUse().getID()); if(decls().size() > 1) { error("several most specific constructors for " + this); for(Iterator iter = decls().iterator(); iter.hasNext(); ) { error(" " + ((ConstructorDecl)iter.next()).signature()); } } } public void ClassInstanceExpr.nameCheck() { super.nameCheck(); if(decl() == illegalConstructor() && decls().size() <= 1) error("can not instantiate " + type().fullName() + " no matching constructor found in " + type().fullName()); else if(decls().size() > 1) { error("several most specific constructors found"); for(Iterator iter = decls().iterator(); iter.hasNext(); ) { error(" " + ((ConstructorDecl)iter.next()).signature()); } } } /* inh TypeDecl SuperConstructorAccess.hostInstance(); inh TypeDecl FieldDeclaration.hostInstance(); inh TypeDecl MethodDeclaration.hostInstance(); inh TypeDecl AbstractDot.hostInstance(); eq Program.getCompilationUnit().hostInstance() = null; eq TypeDecl.getBodyDecl().hostInstance() = isInnerType() ? enclosingType() : null; eq ConstructorDecl.getConstructorInvocation().hostInstance() = null; eq FieldDeclaration.getAbstractVarInit().hostInstance() = isStatic() ? null : hostInstance(); eq MethodDeclaration.getBlock().hostInstance() = isStatic() ? null : hostInstance(); eq AbstractDot.getRight().hostInstance() { if(getLeft().isVarAccess() || getLeft().isMethodAccess()) { return getLeft().type(); } return hostInstance(); } */ public void SuperConstructorAccess.nameCheck() { super.nameCheck(); // 8.8.5.1 TypeDecl c = hostType(); TypeDecl s = c.isClassDecl() && ((ClassDecl)c).hasSuperClass() ? ((ClassDecl)c).getSuperClass() : illegalType(); if(!isQualified() && s.isInnerType()) { if(!c.isInnerType()) { error("" + s.fullName() + " isStatic: " + s.isStatic() + ", enclosingType: " + s.enclosingType().fullName()); error("no enclosing instance for " + s.fullName() + " when accessed in " + this); } /* if(s.isLocalClass()) { TypeDecl o = s.enclosingType(); if(!o.localLookupType(c.name()).contains(c)) error("" + c.fullName() + " is not a member of the enclosing type " + o.fullName()); } else if(s.isInnerType()) { TypeDecl o = s.enclosingType(); if(!c.localLookupType(o.name()).contains(o)) error("" + o.fullName() + " is not a member of the enclosing type " + c.fullName()); } */ } /* if(s.isInnerType() && !s.inStaticContext() && !s.isLocalClass() && !isQualified()) { if(enclosingInstance() == null) { error("no enclosing class to " + c.fullName() + " with respect to the super class " + s.fullName() + " specified"); } else { if(s.isLocal if(!c.enclosedBy(s.enclosingType())) { //else if(!enclosingInstance().instanceOf(s.enclosingType())) { error("the current enclosing class " + enclosingInstance().fullName() + " does not equal the enclosing class " + s.enclosingType().fullName() + " with respect to the super class " + s.fullName() + ", error in " + this); } } */ } public void SuperConstructorDot.nameCheck() { super.nameCheck(); // 8.8.5.1 TypeDecl c = hostType(); TypeDecl s = c.isClassDecl() && ((ClassDecl)c).hasSuperClass() ? ((ClassDecl)c).getSuperClass() : illegalType(); if(!s.isInnerType() || s.inStaticContext()) error("the super type " + s.fullName() + " of " + c.fullName() + " is not an inner class"); else if(!getLeft().type().instanceOf(s.enclosingType())) error("The type of this primary expression, " + getLeft().type().fullName() + " is not enclosing the super type, " + s.fullName() + ", of " + c.fullName()); } syn boolean TypeDecl.hasEnclosingType() = isInnerType() || !inStaticContext(); syn boolean Access.isQualified() = getParent() instanceof AbstractDot && ((AbstractDot)getParent()).getRight() == this; // 8.8.5.1 inh boolean VarAccess.inExplicitConstructorInvocation(); inh boolean MethodAccess.inExplicitConstructorInvocation(); inh boolean SuperAccess.inExplicitConstructorInvocation(); inh boolean ThisAccess.inExplicitConstructorInvocation(); inh boolean ClassInstanceExpr.inExplicitConstructorInvocation(); inh lazy boolean TypeDecl.inExplicitConstructorInvocation(); eq Program.getCompilationUnit().inExplicitConstructorInvocation() = false; //eq Block.getStmt().inExplicitConstructorInvocation() = false; eq ConstructorAccess.getArg().inExplicitConstructorInvocation() = true; eq SuperConstructorAccess.getArg().inExplicitConstructorInvocation() = true; inh boolean ThisDot.inExplicitConstructorInvocation(); eq ThisDot.getRight().inExplicitConstructorInvocation() = inExplicitConstructorInvocation() && !hostType().enclosedBy(getLeft().type()); eq MethodAccess.getArg().inStaticContext() = unqualifiedScope().inStaticContext(); inh boolean Expr.inStaticContext(); inh boolean VarAccess.inStaticContext(); inh boolean MethodAccess.inStaticContext(); inh boolean ThisAccess.inStaticContext(); inh boolean SuperAccess.inStaticContext(); inh lazy boolean AbstractDot.inStaticContext(); inh lazy boolean TypeDecl.inStaticContext(); inh boolean ClassInstanceExpr.inStaticContext(); eq Program.getCompilationUnit().inStaticContext() = false; eq TypeDecl.getBodyDecl().inStaticContext() = isStatic() || inStaticContext(); eq StaticInitializer.getBlock().inStaticContext() = true; eq InstanceInitializer.getBlock().inStaticContext() = false; eq FieldDeclaration.getAbstractVarInit().inStaticContext() = isStatic() || hostType().isInterfaceDecl(); eq MethodDecl.getBlock().inStaticContext() = isStatic(); eq AbstractDot.getRight().inStaticContext() { if(getLeft() instanceof VarAccess || getLeft() instanceof FieldDot) return false; if(getLeft() instanceof MethodDot || getLeft() instanceof MethodAccess) return false; if(getLeft() instanceof ArrayAccess || getLeft() instanceof ArrayDot) return false; if(getLeft() instanceof ClassDot) return false; if(getLeft() instanceof SuperAccess || getLeft() instanceof SuperDot) return false; if(getLeft() instanceof ThisAccess || getLeft() instanceof ThisDot) return false; if(getLeft() instanceof ClassInstanceExpr) return false; /* if(!inStaticContext() && (getLeft() instanceof TypeAccess || getLeft() instanceof TypeDot) && getLeft().type().instanceOf(hostType())) return false; */ if(inStaticContext() || (getLeft() instanceof TypeAccess || getLeft() instanceof TypeDot)) return true; return false; } eq ClassInstanceExpr.getTypeDecl().inStaticContext() = inStaticContext(); eq SuperDot.getRight().inStaticContext() = false; eq ThisDot.getRight().inStaticContext() = false; eq SuperConstructorDot.getLeft().inStaticContext() = hostType().enclosedBy(getLeft().type()) ? false : true; eq MemberClass.getClassDecl().inStaticContext() = false; eq ConstructorDecl.getBlock().inStaticContext() = false; public void ArrayTypeAccess.nameCheck() { if(decl().elementType() == unknownType()) error("no type named " + name()); } public void TypeDot.nameCheck() { ASTNode a = getLeft(); if(!(a instanceof TypeAccess) && !(a instanceof TypeDot) && !(a instanceof PackageAccess) && !(a instanceof PackageDot)) error("can not access the type named " + ((TypeAccess)getRight()).decl().fullName() + " in this context"); } public void ThisDot.nameCheck() { // 15.8.4 if(!hostType().isInnerTypeOf(getLeft().type()) && hostType() != getLeft().type()) error("qualified this must name an enclosing type: " + this); if(inStaticContext()) { error("*** Qualified this may not occur in static context"); } super.nameCheck(); } public void SuperDot.nameCheck() { //System.out.println("SuperDot.nameCheck(): hostType(): " + hostType().fullName() + ", leftType(): " + getLeft().type().fullName()); //if(!hostType().enclosedBy(getLeft().type()) && hostType() != getLeft().type()) if(!hostType().isInnerTypeOf(getLeft().type()) && hostType() != getLeft().type()) error("qualified super must name an enclosing type"); if(inStaticContext()) { error("*** Qualified super may not occur in static context"); } super.nameCheck(); } public void TypeAccess.nameCheck() { if(decl() == unknownType() && decls().size() <= 1) error("no type named " + name()); if(decls().size() > 1) { error("several types named " + name()); for(TypeCollection.TypeIterator iter = decls().iterator(); iter.hasNext(); ) { TypeDecl t = (TypeDecl)iter.next(); error(" " + t.fullName()); } } /* Not sure about this one if(!isQualified() && hostType().isStatic() && !decl().isTopLevelType() && !decl().isStatic() && !hostType().isInnerTypeOf(decl().hostType()) && !hostType().instanceOf(decl().enclosingType())) { System.out.println("HostType: " + hostType().fullName() + ", Decl: " + decl().fullName() + ", Decl.enclosingType(): " + decl().enclosingType().fullName()); error("the static class " + hostType().fullName() + " must not acccess the non-static type " + decl().fullName() + " of the enclosing class"); } */ } public void SuperAccess.nameCheck() { // 8.8.5.1 if(inExplicitConstructorInvocation() && hostType().instanceOf(decl().hostType()) ) error("super may not be accessed in an explicit constructor invocation"); // 8.4.3.2 if(inStaticContext()) error("super may not be accessed in a static context"); } public void ThisAccess.nameCheck() { // 8.8.5.1 if(inExplicitConstructorInvocation()) error("this may not be accessed in an explicit constructor invocation"); // 8.4.3.2 if(inStaticContext()) error("this may not be accessed in static context: " + enclosingStmt()); } public void ClassDot.nameCheck() { ASTNode a = getLeft(); if(!(a instanceof TypeAccess) && !(a instanceof TypeDot)) error("class literal may only contain type names"); } public void VarAccess.nameCheck() { if(decl() == unknownField() && decls().size() <= 1) error("no field named " + getIdUse().getID()); if(decls().size() > 1) { error("several fields named " + getIdUse().getID()); for(Iterator iter = decls().iterator(); iter.hasNext(); ) { Variable v = (Variable)iter.next(); error(" " + v.type().fullName() + "." + v.name() + " declared in " + v.hostType().fullName()); } } // 8.8.5.1 if(inExplicitConstructorInvocation() && !isQualified() && decl().isInstanceVariable() && hostType() == decl().hostType()) error("instance variable " + getIdUse() + " may not be accessed in an explicit constructor invocation"); /* if(inStaticContext() && decl().isInstanceVariable()) error("instance variable " + getIdUse() + " may not be accessed in a static context"); */ Variable v = decl(); if(!v.isFinal() && !v.isClassVariable() && !v.isInstanceVariable() && v.hostType() != hostType()) error("A parameter/variable used but not declared in an inner class must be declared final"); // 8.5,2 /* if(!isQualified() && !decl().isStatic() && !hostType().isInnerTypeOf(decl().hostType()) && !hostType().instanceOf(decl().hostType())) { if(!(hostType().isAnonymous() && decl().isFinal())) error("a static class must not acccess non-static variable of the enclosing class"); } */ // 8.3.2.3 if((decl().isInstanceVariable() || decl().isClassVariable()) && !isQualified()) { if(!hostType().declaredBeforeUse(decl(), getIdUse())) { if(inSameInitializer() && !simpleAssignment() && inDeclaringClass()) { BodyDecl b = getIdUse().closestBodyDecl(hostType()); error("variable " + decl().name() + " is used in " + b + " before it is declared"); } } } } public BodyDecl IdUse.closestBodyDecl(TypeDecl t) { ASTNode node = this; while(!(node.getParent().getParent() instanceof Program) && node.getParent().getParent() != t) { node = node.getParent(); } return (BodyDecl)node; } syn boolean VarAccess.inSameInitializer() { BodyDecl b = getIdUse().closestBodyDecl(decl().hostType()); if(b instanceof FieldDeclaration && ((FieldDeclaration)b).isStatic() == decl().isStatic()) return true; if(b instanceof InstanceInitializer && !decl().isStatic()) return true; if(b instanceof StaticInitializer && decl().isStatic()) return true; return false; } syn boolean VarAccess.simpleAssignment() = isDest() && getParent() instanceof AssignSimpleExpr; syn boolean VarAccess.inDeclaringClass() = hostType() == decl().hostType(); inh boolean TypeDecl.hasPackage(String packageName); inh boolean PackageAccess.hasPackage(String packageName); inh ASTNode TypeDecl.enclosingBlock(); eq MethodDecl.getBlock().enclosingBlock() = this; eq ConstructorDecl.getBlock().enclosingBlock() = this; eq InstanceInitializer.getBlock().enclosingBlock() = this; eq Program.getCompilationUnit().enclosingBlock() = null; public void TypeDecl.nameCheck() { if(isTopLevelType() && lookupType(packageName(), name()) != this) error("duplicate member " + name() + " in compilation unit"); if(!isTopLevelType() && !isAnonymous() && !isLocalClass() && extractSingleType(enclosingType().remoteLookupType(name())) != this) error("duplicate member type " + name() + " in type " + enclosingType().fullName()); // 14.3 if(isLocalClass()) { TypeDecl typeDecl = extractSingleType(lookupType(name())); if(typeDecl != null && typeDecl != this && typeDecl.isLocalClass() && enclosingBlock() == typeDecl.enclosingBlock()) error("local class named " + name() + " may not be redeclared as a local class in the same block"); } if(isNestedType() && hasPackage(fullName())) error("duplicate member class and package " + name()); // 8.1 & 9.1 if(hasEnclosingTypeDecl(name())) { error("type may not have the same simple name as an enclosing type declaration"); } // 8.4.6.4 & 9.4.1 for(Iterator iter = methods().iterator(); iter.hasNext(); ) { MethodDecl m = (MethodDecl)iter.next(); for(Iterator i2 = overrides(m).iterator(); i2.hasNext(); ) { MethodDecl decl = (MethodDecl)i2.next(); //System.out.println("Overriden"); // 8.4.6.1 if(!m.isStatic() && decl.isStatic()) error("an instance method may not override a static method"); // 8.4.6.3 if(m.type() != decl.type()) error("the return type of method " + m.signature() + " in " + m.hostType().fullName() + " does not match the return type of method " + decl.signature() + " in " + decl.hostType().fullName() + " and may thus not be overriden"); // 8.4.4 for(int i = 0; i < m.getNumException(); i++) { Access e = m.getException(i); boolean found = false; for(int j = 0; !found && j < decl.getNumException(); j++) { if(e.type().instanceOf(decl.getException(j).type())) found = true; } if(!found && e.type().isUncheckedException()) error("may not throw more checked exceptions than overridden method"); } // 8.4.6.3 if(decl.isPublic() && !m.isPublic()) error("overriding access modifier error"); // 8.4.6.3 if(decl.isProtected() && !(m.isPublic() || m.isProtected())) error("overriding access modifier error"); // 8.4.6.3 if((!decl.isPrivate() && !decl.isProtected() && !decl.isPublic()) && m.isPrivate()) error("overriding access modifier error"); if(decl.isFinal()) error("method " + m.signature() + " in " + hostType().fullName() + " can not override final method " + decl.signature() + " in " + decl.hostType().fullName()); } for(Iterator i2 = hides(m).iterator(); i2.hasNext(); ) { MethodDecl decl = (MethodDecl)i2.next(); //System.out.println("Hidden"); // 8.4.6.2 if(m.isStatic() && !decl.isStatic()) error("a static method may not hide an instance method"); // 8.4.6.3 if(m.type() != decl.type()) error("can not hide a method with a different return type"); // 8.4.4 for(int i = 0; i < m.getNumException(); i++) { Access e = m.getException(i); boolean found = false; for(int j = 0; !found && j < decl.getNumException(); j++) { if(e.type().instanceOf(decl.getException(j).type())) found = true; } if(!found) error("may not throw more checked exceptions than hidden method"); } // 8.4.6.3 if(decl.isPublic() && !m.isPublic()) error("hiding access modifier error: public method " + decl.signature() + " in " + decl.hostType().fullName() + " is hidden by non public method " + m.signature() + " in " + m.hostType().fullName()); // 8.4.6.3 if(decl.isProtected() && !(m.isPublic() || m.isProtected())) error("hiding access modifier error: protected method " + decl.signature() + " in " + decl.hostType().fullName() + " is hidden by non (public|protected) method " + m.signature() + " in " + m.hostType().fullName()); // 8.4.6.3 if((!decl.isPrivate() && !decl.isProtected() && !decl.isPublic()) && m.isPrivate()) error("hiding access modifier error: default method " + decl.signature() + " in " + decl.hostType().fullName() + " is hidden by private method " + m.signature() + " in " + m.hostType().fullName()); if(decl.isFinal()) error("method " + m.signature() + " in " + hostType().fullName() + " can not hide final method " + decl.signature() + " in " + decl.hostType().fullName()); } if(m.hostType() != this) { MethodCollection list = localLookupMethod(m); for(MethodCollection.MethodIterator i2 = list.iterator(); i2.hasNext(); ) { MethodDecl n = (MethodDecl)i2.next(); if(n != m) { if(n.hostType() != this && m.type() != n.type()) error("multiply inherited methods with the same signature must have the same return type"); if(n.hostType() != this && !m.isAbstract() && m.isStatic()) { error("abstract instance methods may not be implemented by a static method " + m.signature()); } } } } } } public void ClassDecl.nameCheck() { super.nameCheck(); if(hasSuperClass() && !getSuperClassAccess().type().isClassDecl()) error("class may only inherit a class and not " + getSuperClassAccess().type().fullName()); //if(isCircular()) if(hasSuperClass() && getSuperClass() == illegalType()) error("circular inheritance dependency in " + fullName()); } public void InterfaceDecl.nameCheck() { super.nameCheck(); TypeDecl illegalDecl = illegalType(); for(int i = 0; i < getNumSuperInterfaceId(); i++) { TypeDecl typeDecl = getSuperInterfaceId(i).type(); if(typeDecl == illegalDecl) error("circular inheritance dependency in " + fullName()); } } syn boolean TypeDecl.hasEnclosingTypeDecl(String name) { TypeDecl enclosingType = enclosingType(); if(enclosingType != null) { return enclosingType.name().equals(name) || enclosingType.hasEnclosingTypeDecl(name); } return false; } public void FieldDeclaration.nameCheck() { // 8.3 Collection list = hostType().findVariable(getIdDecl()); for(Iterator iter = list.iterator(); iter.hasNext(); ) { Variable v = (Variable)iter.next(); if(v != this && v.hostType() == hostType()) error("field named " + name() + " is multiply declared in type " + hostType().fullName()); } if(isBlank() && isFinal() && isClassVariable()) { boolean found = false; TypeDecl typeDecl = hostType(); for(int i = 0; i < typeDecl.getNumBodyDecl(); i++) { if(typeDecl.getBodyDecl(i) instanceof StaticInitializer) { StaticInitializer s = (StaticInitializer)typeDecl.getBodyDecl(i); if(s.isDAafter(this)) found = true; } else if(typeDecl.getBodyDecl(i) instanceof FieldDeclaration) { FieldDeclaration f = (FieldDeclaration)typeDecl.getBodyDecl(i); if(f.isStatic() && f.isDAafter(this)) found = true; } } if(!found) error("blank final class variable " + name() + " in " + hostType().fullName() + " is not definitely assigned in static initializer"); } if(isBlank() && isFinal() && isInstanceVariable()) { TypeDecl typeDecl = hostType(); boolean found = false; for(int i = 0; !found && i < typeDecl.getNumBodyDecl(); i++) { if(typeDecl.getBodyDecl(i) instanceof FieldDeclaration) { FieldDeclaration f = (FieldDeclaration)typeDecl.getBodyDecl(i); if(!f.isStatic() && f.isDAafter(this)) found = true; } else if(typeDecl.getBodyDecl(i) instanceof InstanceInitializer) { InstanceInitializer ii = (InstanceInitializer)typeDecl.getBodyDecl(i); if(ii.getBlock().isDAafter(this)) found = true; } } for(int i = 0; !found && i < typeDecl.getNumBodyDecl(); i++) { if(typeDecl.getBodyDecl(i) instanceof ConstructorDecl) { ConstructorDecl c = (ConstructorDecl)typeDecl.getBodyDecl(i); if(!c.isDAafter(this)) { error("blank final instance variable " + name() + " in " + hostType().fullName() + " is not definitely assigned after " + c.signature()); } } } } if(isBlank() && hostType().isInterfaceDecl()) { error("variable " + name() + " in " + hostType().fullName() + " which is an interface must have an initializer"); } } public void VariableDeclaration.nameCheck() { //IdUse idUse = new IdUse(getIdDecl().getID()); // Dragons //idUse.setParent(this); Collection decls = outerScope().lookupVariable(getIdDecl().getID()); for(Iterator iter = decls.iterator(); iter.hasNext(); ) { Variable var = (Variable)iter.next(); if(var instanceof VariableDeclaration) { VariableDeclaration decl = (VariableDeclaration)var; if(decl.enclosingBodyDecl() == enclosingBodyDecl()) error("duplicate declaration of local variable " + name() + " in enclosing scope"); } // 8.4.1 else if(var instanceof ParameterDeclaration) { ParameterDeclaration decl = (ParameterDeclaration)var; if(decl.enclosingBodyDecl() == enclosingBodyDecl()) error("duplicate declaration of local variable and parameter " + name()); } } if(getParent().getParent() instanceof Block) { Block block = (Block)getParent().getParent(); for(int i = 0; i < block.getNumStmt(); i++) { if(block.getStmt(i) instanceof Variable) { Variable v = (Variable)block.getStmt(i); if(v.name().equals(getIdDecl().getID()) && v != this) { error("duplicate declaration of local variable " + name()); } } } } } public void ParameterDeclaration.nameCheck() { //IdUse idUse = new IdUse(getIdDecl().getID()); // Dragons //idUse.setParent(this); Collection decls = outerScope().lookupVariable(getIdDecl().getID()); for(Iterator iter = decls.iterator(); iter.hasNext(); ) { Variable var = (Variable)iter.next(); if(var instanceof VariableDeclaration) { VariableDeclaration decl = (VariableDeclaration)var; if(decl.enclosingBodyDecl() == enclosingBodyDecl()) error("duplicate declaration of local variable " + name()); } else if(var instanceof ParameterDeclaration) { ParameterDeclaration decl = (ParameterDeclaration)var; if(decl.enclosingBodyDecl() == enclosingBodyDecl()) error("duplicate declaration of local variable " + name()); } } // 8.4.1 if(!/*varScope().*/lookupVariable(name()).contains(this)) { error("duplicate declaration of parameter " + name()); } } public void LabelStmt.nameCheck() { LabelStmt stmt = lookupLabel(getLabel().getID()); if(stmt != null) { if(stmt.enclosingBodyDecl() == enclosingBodyDecl()) { error("Labels can not shadow labels in the same member"); } } } public void BreakStmt.nameCheck() { if(targetStmt() == null) { if(hasLabel()) error("labeled break must have visible matching label"); else error("plain break must occur in a loop statement of switch"); } } public void ContinueStmt.nameCheck() { if(targetStmt() == null) { if(hasLabel()) error("labeled continue must have visible matching label"); else error("plain continue must occur in a loop statement"); } if(hasLabel() && targetStmt() != null && !targetStmt().isLoop() && !(targetStmt() instanceof TryStmt)) error("***A label targeted by continue must have a loop as its statment"); } syn boolean Stmt.isLoop() = false; eq ForStmt.isLoop() = true; eq WhileStmt.isLoop() = true; eq DoStmt.isLoop() = true; public void ReturnStmt.nameCheck() { // 8.4.5 8.8.5 if(hostBodyDecl().isVoid() && hasResult()) error("return stmt may not have an expression in void methods"); // 8.4.5 if(!hostBodyDecl().isVoid() && !hasResult()) error("return stmt must have an expression in non void methods"); if(hostBodyDecl() instanceof InstanceInitializer || hostBodyDecl() instanceof StaticInitializer) error("Initializers may not return"); } public void ConstCase.nameCheck() { if(getValue().isConstant() && bind(this) != this) { error("constant expression " + getValue() + " is multiply declared in two case statements"); } } public void DefaultCase.nameCheck() { if(bind(this) != this) { error("only one default case statement allowed"); } } inh lazy Case Case.bind(Case c); eq SwitchStmt.getCase().bind(Case c) { for(int i = 0; i < getNumCase(); i++) if(getCase(i).constValue(c)) return getCase(i); return null; } syn boolean TypeDecl.assignableToInt() = false; eq IntegralType.assignableToInt() = true; eq LongType.assignableToInt() = false; syn boolean Case.constValue(Case c); eq ConstCase.constValue(Case c) { if(!(c instanceof ConstCase) || !getValue().isConstant()) return false; if(!getValue().type().assignableToInt() || !((ConstCase)c).getValue().type().assignableToInt()) return false; return getValue().constant().intValue() == ((ConstCase)c).getValue().constant().intValue(); } eq DefaultCase.constValue(Case c) = c instanceof DefaultCase; }