001 /* 002 * The JastAdd Extensible Java Compiler (http://jastadd.org) is covered 003 * by the modified BSD License. You should have received a copy of the 004 * modified BSD license with this compiler. 005 * 006 * Copyright (c) 2005-2008, Torbjorn Ekman 007 * All rights reserved. 008 */ 009 010 aspect TypeHierarchyCheck { 011 inh String Expr.methodHost(); 012 eq TypeDecl.getBodyDecl().methodHost() = typeName(); 013 eq AbstractDot.getRight().methodHost() = getLeft().type().typeName(); 014 eq Program.getChild().methodHost() { 015 throw new Error("Needs extra equation for methodHost()"); 016 } 017 eq MethodAccess.getChild().methodHost() = unqualifiedScope().methodHost(); 018 eq ConstructorAccess.getChild().methodHost() = unqualifiedScope().methodHost(); 019 020 syn boolean Expr.isUnknown() = type().isUnknown(); 021 eq PackageAccess.isUnknown() = !hasPackage(packageName()); 022 023 public void MethodAccess.nameCheck() { 024 if(isQualified() && qualifier().isPackageAccess() && !qualifier().isUnknown()) 025 error("The method " + decl().signature() + 026 " can not be qualified by a package name."); 027 if(isQualified() && decl().isAbstract() && qualifier().isSuperAccess()) 028 error("may not access abstract methods in superclass"); 029 if(decls().isEmpty() && (!isQualified() || !qualifier().isUnknown())) { 030 StringBuffer s = new StringBuffer(); 031 s.append("no method named " + name()); 032 s.append("("); 033 for(int i = 0; i < getNumArg(); i++) { 034 if(i != 0) 035 s.append(", "); 036 s.append(getArg(i).type().typeName()); 037 } 038 s.append(")" + " in " + methodHost() + " matches."); 039 if(singleCandidateDecl() != null) 040 s.append(" However, there is a method " + singleCandidateDecl().signature()); 041 error(s.toString()); 042 } 043 if(decls().size() > 1) { 044 boolean allAbstract = true; 045 for(Iterator iter = decls().iterator(); iter.hasNext() && allAbstract; ) { 046 MethodDecl m = (MethodDecl)iter.next(); 047 if(!m.isAbstract() && !m.hostType().isObject()) 048 allAbstract = false; 049 } 050 if(!allAbstract && validArgs()) { 051 StringBuffer s = new StringBuffer(); 052 s.append("several most specific methods for " + this + "\n"); 053 for(Iterator iter = decls().iterator(); iter.hasNext(); ) { 054 MethodDecl m = (MethodDecl)iter.next(); 055 s.append(" " + m.signature() + " in " + m.hostType().typeName() + "\n"); 056 } 057 error(s.toString()); 058 } 059 060 } 061 } 062 063 public void SuperConstructorAccess.nameCheck() { 064 super.nameCheck(); 065 // 8.8.5.1 066 TypeDecl c = hostType(); 067 TypeDecl s = c.isClassDecl() && ((ClassDecl)c).hasSuperclass() ? ((ClassDecl)c).superclass() : unknownType(); 068 if(isQualified()) { 069 if(!s.isInnerType() || s.inStaticContext()) 070 error("the super type " + s.typeName() + " of " + c.typeName() + 071 " is not an inner class"); 072 073 else if(!qualifier().type().instanceOf(s.enclosingType())) 074 error("The type of this primary expression, " + 075 qualifier().type().typeName() + " is not enclosing the super type, " + 076 s.typeName() + ", of " + c.typeName()); 077 } 078 if(!isQualified() && s.isInnerType()) { 079 if(!c.isInnerType()) { 080 error("no enclosing instance for " + s.typeName() + " when accessed in " + this); 081 } 082 } 083 if(s.isInnerType() && hostType().instanceOf(s.enclosingType())) 084 error("cannot reference this before supertype constructor has been called"); 085 } 086 087 public void SuperAccess.nameCheck() { 088 if(isQualified()) { 089 if(!hostType().isInnerTypeOf(decl()) && hostType() != decl()) 090 error("qualified super must name an enclosing type"); 091 if(inStaticContext()) { 092 error("*** Qualified super may not occur in static context"); 093 } 094 } 095 // 8.8.5.1 096 if(inExplicitConstructorInvocation() && hostType().instanceOf(decl().hostType()) ) 097 error("super may not be accessed in an explicit constructor invocation"); 098 // 8.4.3.2 099 if(inStaticContext()) 100 error("super may not be accessed in a static context"); 101 } 102 103 public void ThisAccess.nameCheck() { 104 // 8.8.5.1 105 if(inExplicitConstructorInvocation() && hostType() == type()) 106 error("this may not be accessed in an explicit constructor invocation"); 107 else if(isQualified()) { 108 // 15.8.4 109 if(inStaticContext()) 110 error("qualified this may not occur in static context"); 111 else if(!hostType().isInnerTypeOf(decl()) && hostType() != decl()) 112 error("qualified this must name an enclosing type: " + getParent()); 113 } 114 // 8.4.3.2 115 else if(!isQualified() && inStaticContext()) 116 error("this may not be accessed in static context: " + enclosingStmt()); 117 } 118 119 120 121 // 8.8.5.1 122 inh boolean VarAccess.inExplicitConstructorInvocation(); 123 inh boolean MethodAccess.inExplicitConstructorInvocation(); 124 inh boolean SuperAccess.inExplicitConstructorInvocation(); 125 inh boolean ThisAccess.inExplicitConstructorInvocation(); 126 inh boolean ClassInstanceExpr.inExplicitConstructorInvocation(); 127 inh lazy boolean TypeDecl.inExplicitConstructorInvocation(); 128 eq Program.getChild().inExplicitConstructorInvocation() = false; 129 130 eq ConstructorAccess.getArg().inExplicitConstructorInvocation() = true; 131 eq SuperConstructorAccess.getArg().inExplicitConstructorInvocation() = true; 132 eq ConstructorDecl.getConstructorInvocation().inExplicitConstructorInvocation() = true; 133 134 inh boolean Expr.inStaticContext(); // SuperAccess, ThisAccess, ClassInstanceExpr, MethodAccess 135 inh lazy boolean TypeDecl.inStaticContext(); 136 137 eq Program.getChild().inStaticContext() = false; 138 eq TypeDecl.getBodyDecl().inStaticContext() = isStatic() || inStaticContext(); 139 eq StaticInitializer.getBlock().inStaticContext() = true; 140 eq InstanceInitializer.getBlock().inStaticContext() = false; 141 eq FieldDeclaration.getInit().inStaticContext() = isStatic() || hostType().isInterfaceDecl(); 142 eq MethodDecl.getBlock().inStaticContext() = isStatic(); 143 eq ConstructorDecl.getBlock().inStaticContext() = false; 144 eq ConstructorDecl.getConstructorInvocation().inStaticContext() = false; 145 eq MemberClassDecl.getClassDecl().inStaticContext() = false; 146 147 eq ClassInstanceExpr.getTypeDecl().inStaticContext() = isQualified() ? 148 qualifier().staticContextQualifier() : inStaticContext(); 149 150 syn boolean Expr.staticContextQualifier() = false; 151 eq ParExpr.staticContextQualifier() = getExpr().staticContextQualifier(); 152 eq CastExpr.staticContextQualifier() = getExpr().staticContextQualifier(); 153 eq AbstractDot.staticContextQualifier() = lastAccess().staticContextQualifier(); 154 eq TypeAccess.staticContextQualifier() = true; 155 eq ArrayTypeAccess.staticContextQualifier() = true; 156 157 public void TypeDecl.typeCheck() { 158 // 8.4.6.4 & 9.4.1 159 for(Iterator iter1 = localMethodsIterator(); iter1.hasNext(); ) { 160 MethodDecl m = (MethodDecl)iter1.next(); 161 ASTNode target = m.hostType() == this ? (ASTNode)m : (ASTNode)this; 162 163 //for(Iterator i2 = overrides(m).iterator(); i2.hasNext(); ) { 164 for(Iterator i2 = ancestorMethods(m.signature()).iterator(); i2.hasNext(); ) { 165 MethodDecl decl = (MethodDecl)i2.next(); 166 if(m.overrides(decl)) { 167 // 8.4.6.1 168 if(!m.isStatic() && decl.isStatic()) 169 target.error("an instance method may not override a static method"); 170 171 // regardless of overriding 172 // 8.4.6.3 173 if(!m.mayOverrideReturn(decl)) 174 target.error("the return type of method " + m.signature() + " in " + m.hostType().typeName() + " does not match the return type of method " + decl.signature() + " in " + decl.hostType().typeName() + " and may thus not be overriden"); 175 176 // regardless of overriding 177 // 8.4.4 178 for(int i = 0; i < m.getNumException(); i++) { 179 Access e = m.getException(i); 180 boolean found = false; 181 for(int j = 0; !found && j < decl.getNumException(); j++) { 182 if(e.type().instanceOf(decl.getException(j).type())) 183 found = true; 184 } 185 if(!found && e.type().isUncheckedException()) 186 target.error(m.signature() + " in " + m.hostType().typeName() + " may not throw more checked exceptions than overridden method " + 187 decl.signature() + " in " + decl.hostType().typeName()); 188 } 189 // 8.4.6.3 190 if(decl.isPublic() && !m.isPublic()) 191 target.error("overriding access modifier error"); 192 // 8.4.6.3 193 if(decl.isProtected() && !(m.isPublic() || m.isProtected())) 194 target.error("overriding access modifier error"); 195 // 8.4.6.3 196 if((!decl.isPrivate() && !decl.isProtected() && !decl.isPublic()) && m.isPrivate()) 197 target.error("overriding access modifier error"); 198 199 // regardless of overriding 200 if(decl.isFinal()) 201 target.error("method " + m.signature() + " in " + hostType().typeName() + " can not override final method " + decl.signature() + " in " + decl.hostType().typeName()); 202 } 203 if(m.hides(decl)) { 204 // 8.4.6.2 205 if(m.isStatic() && !decl.isStatic()) 206 target.error("a static method may not hide an instance method"); 207 // 8.4.6.3 208 if(!m.mayOverrideReturn(decl)) 209 target.error("can not hide a method with a different return type"); 210 // 8.4.4 211 for(int i = 0; i < m.getNumException(); i++) { 212 Access e = m.getException(i); 213 boolean found = false; 214 for(int j = 0; !found && j < decl.getNumException(); j++) { 215 if(e.type().instanceOf(decl.getException(j).type())) 216 found = true; 217 } 218 if(!found) 219 target.error("may not throw more checked exceptions than hidden method"); 220 } 221 // 8.4.6.3 222 if(decl.isPublic() && !m.isPublic()) 223 target.error("hiding access modifier error: public method " + decl.signature() + " in " + decl.hostType().typeName() + " is hidden by non public method " + m.signature() + " in " + m.hostType().typeName()); 224 // 8.4.6.3 225 if(decl.isProtected() && !(m.isPublic() || m.isProtected())) 226 target.error("hiding access modifier error: protected method " + decl.signature() + " in " + decl.hostType().typeName() + " is hidden by non (public|protected) method " + m.signature() + " in " + m.hostType().typeName()); 227 // 8.4.6.3 228 if((!decl.isPrivate() && !decl.isProtected() && !decl.isPublic()) && m.isPrivate()) 229 target.error("hiding access modifier error: default method " + decl.signature() + " in " + decl.hostType().typeName() + " is hidden by private method " + m.signature() + " in " + m.hostType().typeName()); 230 if(decl.isFinal()) 231 target.error("method " + m.signature() + " in " + hostType().typeName() + " can not hide final method " + decl.signature() + " in " + decl.hostType().typeName()); 232 } 233 } 234 } 235 } 236 237 syn boolean MethodDecl.mayOverrideReturn(MethodDecl m) = type() == m.type(); 238 239 public void ClassDecl.nameCheck() { 240 super.nameCheck(); 241 if(hasSuperClassAccess() && !getSuperClassAccess().type().isClassDecl()) 242 error("class may only inherit a class and not " + getSuperClassAccess().type().typeName()); 243 if(isObject() && hasSuperClassAccess()) 244 error("class Object may not have superclass"); 245 if(isObject() && getNumImplements() != 0) 246 error("class Object may not implement interfaces"); 247 248 // 8.1.3 249 if(isCircular()) 250 error("circular inheritance dependency in " + typeName()); 251 252 // 8.1.4 253 HashSet set = new HashSet(); 254 for(int i = 0; i < getNumImplements(); i++) { 255 TypeDecl decl = getImplements(i).type(); 256 if(!decl.isInterfaceDecl() && !decl.isUnknown()) 257 error("type " + fullName() + " tries to implement non interface type " + decl.fullName()); 258 if(set.contains(decl)) 259 error("type " + decl.fullName() + " mentionened multiple times in implements clause"); 260 set.add(decl); 261 } 262 263 for(Iterator iter = interfacesMethodsIterator(); iter.hasNext(); ) { 264 MethodDecl m = (MethodDecl)iter.next(); 265 if(localMethodsSignature(m.signature()).isEmpty()) { 266 SimpleSet s = superclass().methodsSignature(m.signature()); 267 for(Iterator i2 = s.iterator(); i2.hasNext(); ) { 268 MethodDecl n = (MethodDecl)i2.next(); 269 if(n.accessibleFrom(this)) { 270 interfaceMethodCompatibleWithInherited(m, n); 271 } 272 } 273 if(s.isEmpty()) { 274 for(Iterator i2 = interfacesMethodsSignature(m.signature()).iterator(); i2.hasNext(); ) { 275 MethodDecl n = (MethodDecl)i2.next(); 276 if(!n.mayOverrideReturn(m) && !m.mayOverrideReturn(n)) 277 error("Xthe return type of method " + m.signature() + " in " + m.hostType().typeName() + 278 " does not match the return type of method " + n.signature() + " in " + 279 n.hostType().typeName() + " and may thus not be overriden"); 280 } 281 } 282 } 283 } 284 } 285 286 private void ClassDecl.interfaceMethodCompatibleWithInherited(MethodDecl m, MethodDecl n) { 287 if(n.isStatic()) 288 error("Xa static method may not hide an instance method"); 289 if(!n.isAbstract() && !n.isPublic()) 290 error("Xoverriding access modifier error for " + m.signature() + " in " + m.hostType().typeName() + " and " + n.hostType().typeName()); 291 if(!n.mayOverrideReturn(m) && !m.mayOverrideReturn(m)) 292 error("Xthe return type of method " + m.signature() + " in " + m.hostType().typeName() + 293 " does not match the return type of method " + n.signature() + " in " + 294 n.hostType().typeName() + " and may thus not be overriden"); 295 if(!n.isAbstract()) { 296 // n implements and overrides method m in the interface 297 // may not throw more checked exceptions 298 for(int i = 0; i < n.getNumException(); i++) { 299 Access e = n.getException(i); 300 boolean found = false; 301 for(int j = 0; !found && j < m.getNumException(); j++) { 302 if(e.type().instanceOf(m.getException(j).type())) 303 found = true; 304 } 305 if(!found && e.type().isUncheckedException()) 306 error("X" + n.signature() + " in " + n.hostType().typeName() + " may not throw more checked exceptions than overridden method " + 307 m.signature() + " in " + m.hostType().typeName()); 308 } 309 } 310 } 311 312 public void InterfaceDecl.nameCheck() { 313 super.nameCheck(); 314 if(isCircular()) 315 error("circular inheritance dependency in " + typeName()); 316 else { 317 for(int i = 0; i < getNumSuperInterfaceId(); i++) { 318 TypeDecl typeDecl = getSuperInterfaceId(i).type(); 319 if(typeDecl.isCircular()) 320 error("circular inheritance dependency in " + typeName()); 321 } 322 } 323 for(Iterator iter = methodsSignatureMap().values().iterator(); iter.hasNext(); ) { 324 SimpleSet set = (SimpleSet)iter.next(); 325 if(set.size() > 1) { 326 Iterator i2 = set.iterator(); 327 MethodDecl m = (MethodDecl)i2.next(); 328 while(i2.hasNext()) { 329 MethodDecl n = (MethodDecl)i2.next(); 330 if(!n.mayOverrideReturn(m) && !m.mayOverrideReturn(n)) 331 error("multiply inherited methods with the same signature must have the same return type"); 332 } 333 } 334 } 335 } 336 } 337 338