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 import java.util.*; 011 import java.util.ArrayList; 012 013 aspect LookupMethod { 014 inh MethodDecl MethodDecl.unknownMethod(); 015 inh MethodDecl MethodAccess.unknownMethod(); 016 017 syn Expr Access.unqualifiedScope() = isQualified() ? nestedScope() : this; 018 inh Expr Access.nestedScope(); 019 eq AbstractDot.getRight().nestedScope() = isQualified() ? nestedScope() : this; 020 eq AbstractDot.getLeft().nestedScope() = isQualified() ? nestedScope() : this; 021 eq Program.getChild().nestedScope() { throw new UnsupportedOperationException(); } 022 023 inh Collection Expr.lookupMethod(String name); 024 inh Collection Stmt.lookupMethod(String name); 025 inh Collection BodyDecl.lookupMethod(String name); 026 inh lazy Collection TypeDecl.lookupMethod(String name); 027 028 eq MethodAccess.getArg().lookupMethod(String name) = unqualifiedScope().lookupMethod(name); 029 eq ConstructorAccess.getArg().lookupMethod(String name) = unqualifiedScope().lookupMethod(name); 030 eq ArrayAccess.getExpr().lookupMethod(String name) = unqualifiedScope().lookupMethod(name); 031 eq ArrayTypeWithSizeAccess.getExpr().lookupMethod(String name) = unqualifiedScope().lookupMethod(name); 032 033 eq Program.getChild().lookupMethod(String name) = Collections.EMPTY_LIST; 034 eq TypeDecl.getBodyDecl(int i).lookupMethod(String name) = unqualifiedLookupMethod(name); 035 036 syn lazy Collection TypeDecl.unqualifiedLookupMethod(String name) { 037 Collection c = memberMethods(name); 038 if(!c.isEmpty()) return c; 039 if(isInnerType()) 040 return lookupMethod(name); 041 return removeInstanceMethods(lookupMethod(name)); 042 } 043 044 // in explicit constructor invocation 045 eq ConstructorDecl.getConstructorInvocation().lookupMethod(String name) { 046 Collection c = new ArrayList(); 047 for(Iterator iter = lookupMethod(name).iterator(); iter.hasNext(); ) { 048 MethodDecl m = (MethodDecl)iter.next(); 049 if(!hostType().memberMethods(name).contains(m) || m.isStatic()) 050 c.add(m); 051 } 052 return c; 053 } 054 public static Collection ASTNode.removeInstanceMethods(Collection c) { 055 c = new LinkedList(c); 056 for(Iterator iter = c.iterator(); iter.hasNext(); ) { 057 MethodDecl m = (MethodDecl)iter.next(); 058 if(!m.isStatic()) 059 iter.remove(); 060 } 061 return c; 062 } 063 064 eq AbstractDot.getRight().lookupMethod(String name) = getLeft().type().memberMethods(name); 065 066 syn MethodDecl MethodAccess.singleCandidateDecl() { 067 MethodDecl result = null; 068 for(Iterator iter = lookupMethod(name()).iterator(); iter.hasNext(); ) { 069 MethodDecl m = (MethodDecl)iter.next(); 070 if(result == null) 071 result = m; 072 else if(m.getNumParameter() == getNumArg() && result.getNumParameter() != getNumArg()) 073 result = m; 074 } 075 return result; 076 } 077 078 protected SimpleSet MethodAccess.maxSpecific(Collection candidates) { 079 SimpleSet maxSpecific = SimpleSet.emptySet; 080 for(Iterator iter = candidates.iterator(); iter.hasNext(); ) { 081 MethodDecl decl = (MethodDecl)iter.next(); 082 if(applicable(decl) && accessible(decl)) { 083 if(maxSpecific.isEmpty()) 084 maxSpecific = maxSpecific.add(decl); 085 else { 086 if(decl.moreSpecificThan((MethodDecl)maxSpecific.iterator().next())) 087 maxSpecific = SimpleSet.emptySet.add(decl); 088 else if(!((MethodDecl)maxSpecific.iterator().next()).moreSpecificThan(decl)) 089 maxSpecific = maxSpecific.add(decl); 090 } 091 } 092 } 093 return maxSpecific; 094 } 095 096 syn lazy SimpleSet MethodAccess.decls() { 097 SimpleSet maxSpecific = maxSpecific(lookupMethod(name())); 098 if(isQualified() ? qualifier().staticContextQualifier() : inStaticContext()) 099 maxSpecific = removeInstanceMethods(maxSpecific); 100 return maxSpecific; 101 } 102 103 syn lazy MethodDecl MethodAccess.decl() { 104 SimpleSet decls = decls(); 105 if(decls.size() == 1) 106 return (MethodDecl)decls.iterator().next(); 107 108 // 8.4.6.4 - only return the first method in case of multply inherited abstract methods 109 boolean allAbstract = true; 110 for(Iterator iter = decls.iterator(); iter.hasNext() && allAbstract; ) { 111 MethodDecl m = (MethodDecl)iter.next(); 112 if(!m.isAbstract() && !m.hostType().isObject()) 113 allAbstract = false; 114 } 115 if(decls.size() > 1 && allAbstract) 116 return (MethodDecl)decls.iterator().next(); 117 return unknownMethod(); 118 } 119 private static SimpleSet MethodAccess.removeInstanceMethods(SimpleSet c) { 120 SimpleSet set = SimpleSet.emptySet; 121 for(Iterator iter = c.iterator(); iter.hasNext(); ) { 122 MethodDecl m = (MethodDecl)iter.next(); 123 if(m.isStatic()) 124 set = set.add(m); 125 } 126 return set; 127 } 128 } 129 130 aspect MethodDecl { 131 syn String MethodDecl.name() = getID(); 132 133 // 8.4.2 134 syn lazy String MethodDecl.signature() { 135 StringBuffer s = new StringBuffer(); 136 s.append(name() + "("); 137 for(int i = 0; i < getNumParameter(); i++) { 138 if(i != 0) s.append(", "); 139 s.append(getParameter(i).type().typeName()); 140 } 141 s.append(")"); 142 return s.toString(); 143 } 144 145 // 8.4.2 Method Signature 146 syn boolean MethodDecl.sameSignature(MethodDecl m) = signature().equals(m.signature()); 147 148 syn lazy boolean MethodDecl.moreSpecificThan(MethodDecl m) { 149 if(getNumParameter() == 0) 150 return false; 151 for(int i = 0; i < getNumParameter(); i++) { 152 if(!getParameter(i).type().instanceOf(m.getParameter(i).type())) 153 return false; 154 } 155 return true; 156 } 157 158 public boolean MethodAccess.applicable(MethodDecl decl) { 159 if(getNumArg() != decl.getNumParameter()) 160 return false; 161 if(!name().equals(decl.name())) 162 return false; 163 for(int i = 0; i < getNumArg(); i++) { 164 if(!getArg(i).type().instanceOf(decl.getParameter(i).type())) 165 return false; 166 } 167 return true; 168 } 169 170 syn boolean MethodAccess.accessible(MethodDecl m) { 171 if(!isQualified()) 172 return true; 173 if(!m.accessibleFrom(hostType())) 174 return false; 175 // the method is not accessible if the type is not accessible 176 if(!qualifier().type().accessibleFrom(hostType())) 177 return false; 178 // 6.6.2.1 - include qualifier type for protected access 179 if(m.isProtected() && !m.hostPackage().equals(hostPackage()) 180 && !m.isStatic() && !qualifier().isSuperAccess()) { 181 return hostType().mayAccess(this, m); 182 } 183 return true; 184 } 185 186 /** 187 * @return true if the method access may access the method 188 */ 189 public boolean TypeDecl.mayAccess(MethodAccess access, MethodDecl method) { 190 if (instanceOf(method.hostType()) 191 && access.qualifier().type().instanceOf(this)) 192 return true; 193 194 if (isNestedType()) 195 return enclosingType().mayAccess(access, method); 196 else 197 return false; 198 } 199 200 syn lazy boolean MethodDecl.overrides(MethodDecl m) = 201 !isStatic() && !m.isPrivate() && m.accessibleFrom(hostType()) && 202 hostType().instanceOf(m.hostType()) && m.signature().equals(signature()); 203 204 syn lazy boolean MethodDecl.hides(MethodDecl m) = 205 isStatic() && !m.isPrivate() && m.accessibleFrom(hostType()) && 206 hostType().instanceOf(m.hostType()) && m.signature().equals(signature()); 207 } 208 209 aspect MemberMethods { 210 syn Collection TypeDecl.memberMethods(String name) { 211 Collection c = (Collection)methodsNameMap().get(name); 212 if(c != null) return c; 213 return Collections.EMPTY_LIST; 214 } 215 // name -> Collection 216 syn lazy HashMap TypeDecl.methodsNameMap() { 217 HashMap map = new HashMap(); 218 for(Iterator iter = methodsIterator(); iter.hasNext(); ) { 219 MethodDecl m = (MethodDecl)iter.next(); 220 ArrayList list = (ArrayList)map.get(m.name()); 221 if(list == null) { 222 list = new ArrayList(4); 223 map.put(m.name(), list); 224 } 225 list.add(m); 226 } 227 return map; 228 } 229 230 231 public Iterator TypeDecl.localMethodsIterator() { 232 return new Iterator() { 233 private Iterator outer = localMethodsSignatureMap().values().iterator(); 234 private Iterator inner = null; 235 public boolean hasNext() { 236 if((inner == null || !inner.hasNext()) && outer.hasNext()) 237 inner = ((SimpleSet)outer.next()).iterator(); 238 return inner == null ? false : inner.hasNext(); 239 } 240 public Object next() { 241 return inner.next(); 242 } 243 public void remove() { throw new UnsupportedOperationException(); } 244 }; 245 //return localMethodsSignatureMap().values().iterator(); 246 } 247 syn SimpleSet TypeDecl.localMethodsSignature(String signature) { 248 SimpleSet set = (SimpleSet)localMethodsSignatureMap().get(signature); 249 if(set != null) return set; 250 return SimpleSet.emptySet; 251 } 252 // signature -> method declaration 253 syn lazy HashMap TypeDecl.localMethodsSignatureMap() { 254 HashMap map = new HashMap(getNumBodyDecl()); 255 for(int i = 0; i < getNumBodyDecl(); i++) { 256 if(getBodyDecl(i) instanceof MethodDecl) { 257 MethodDecl decl = (MethodDecl)getBodyDecl(i); 258 map.put(decl.signature(), decl); 259 } 260 } 261 return map; 262 } 263 264 // iterator over all methods in implemented interfaces 265 public Iterator ClassDecl.interfacesMethodsIterator() { 266 return new Iterator() { 267 private Iterator outer = interfacesMethodsSignatureMap().values().iterator(); 268 private Iterator inner = null; 269 public boolean hasNext() { 270 if((inner == null || !inner.hasNext()) && outer.hasNext()) 271 inner = ((SimpleSet)outer.next()).iterator(); 272 return inner == null ? false : inner.hasNext(); 273 } 274 public Object next() { 275 return inner.next(); 276 } 277 public void remove() { throw new UnsupportedOperationException(); } 278 }; 279 } 280 syn SimpleSet ClassDecl.interfacesMethodsSignature(String signature) { 281 SimpleSet set = (SimpleSet)interfacesMethodsSignatureMap().get(signature); 282 if(set != null) return set; 283 return SimpleSet.emptySet; 284 } 285 // signature -> set of method declarations 286 syn lazy HashMap ClassDecl.interfacesMethodsSignatureMap() { 287 HashMap map = new HashMap(); 288 for(Iterator iter = interfacesIterator(); iter.hasNext(); ) { 289 TypeDecl typeDecl = (InterfaceDecl)iter.next(); 290 for(Iterator i2 = typeDecl.methodsIterator(); i2.hasNext(); ) { 291 MethodDecl m = (MethodDecl)i2.next(); 292 putSimpleSetElement(map, m.signature(), m); 293 } 294 } 295 return map; 296 } 297 298 // iterate over all member methods in this type 299 public Iterator TypeDecl.methodsIterator() { 300 return new Iterator() { 301 private Iterator outer = methodsSignatureMap().values().iterator(); 302 private Iterator inner = null; 303 public boolean hasNext() { 304 if((inner == null || !inner.hasNext()) && outer.hasNext()) 305 inner = ((SimpleSet)outer.next()).iterator(); 306 return inner != null ? inner.hasNext() : false; 307 } 308 public Object next() { 309 return inner.next(); 310 } 311 public void remove() { throw new UnsupportedOperationException(); } 312 }; 313 } 314 315 syn SimpleSet TypeDecl.methodsSignature(String signature) { 316 SimpleSet set = (SimpleSet)methodsSignatureMap().get(signature); 317 if(set != null) return set; 318 return SimpleSet.emptySet; 319 } 320 // signature -> SimpleSet 321 syn lazy HashMap TypeDecl.methodsSignatureMap() = localMethodsSignatureMap(); 322 eq ClassDecl.methodsSignatureMap() { 323 HashMap map = new HashMap(localMethodsSignatureMap()); 324 if(hasSuperclass()) { 325 for(Iterator iter = superclass().methodsIterator(); iter.hasNext(); ) { 326 MethodDecl m = (MethodDecl)iter.next(); 327 if(!m.isPrivate() && m.accessibleFrom(this) && !localMethodsSignatureMap().containsKey(m.signature())) 328 putSimpleSetElement(map, m.signature(), m); 329 } 330 } 331 for(Iterator outerIter = interfacesIterator(); outerIter.hasNext(); ) { 332 TypeDecl typeDecl = (TypeDecl)outerIter.next(); 333 for(Iterator iter = typeDecl.methodsIterator(); iter.hasNext(); ) { 334 MethodDecl m = (MethodDecl)iter.next(); 335 if(!m.isPrivate() && m.accessibleFrom(this) && !localMethodsSignatureMap().containsKey(m.signature())) 336 if(allMethodsAbstract((SimpleSet)map.get(m.signature()))) 337 putSimpleSetElement(map, m.signature(), m); 338 } 339 } 340 return map; 341 } 342 eq InterfaceDecl.methodsSignatureMap() { 343 HashMap map = new HashMap(localMethodsSignatureMap()); 344 for(Iterator outerIter = superinterfacesIterator(); outerIter.hasNext(); ) { 345 TypeDecl typeDecl = (TypeDecl)outerIter.next(); 346 for(Iterator iter = typeDecl.methodsIterator(); iter.hasNext(); ) { 347 MethodDecl m = (MethodDecl)iter.next(); 348 if(!m.isPrivate() && m.accessibleFrom(this) && !localMethodsSignatureMap().containsKey(m.signature())) 349 putSimpleSetElement(map, m.signature(), m); 350 } 351 } 352 for(Iterator iter = typeObject().methodsIterator(); iter.hasNext(); ) { 353 MethodDecl m = (MethodDecl)iter.next(); 354 if(m.isPublic() && !map.containsKey(m.signature())) 355 putSimpleSetElement(map, m.signature(), m); 356 } 357 return map; 358 } 359 protected static void ASTNode.putSimpleSetElement(HashMap map, Object key, Object value) { 360 SimpleSet set = (SimpleSet)map.get(key); 361 if(set == null) set = SimpleSet.emptySet; 362 map.put(key, set.add(value)); 363 } 364 protected boolean TypeDecl.allMethodsAbstract(SimpleSet set) { 365 if(set == null) return true; 366 for(Iterator iter = set.iterator(); iter.hasNext(); ) { 367 MethodDecl m = (MethodDecl)iter.next(); 368 if(!m.isAbstract()) 369 return false; 370 } 371 return true; 372 } 373 } 374 375 aspect AncestorMethods { 376 // methods with the same signature declared in ancestors 377 // this is used when checking correct overriding, hiding, and implementation of abstract methods 378 syn lazy SimpleSet TypeDecl.ancestorMethods(String signature) = SimpleSet.emptySet; 379 380 eq ClassDecl.ancestorMethods(String signature) { 381 SimpleSet set = SimpleSet.emptySet; 382 if(hasSuperclass()) { 383 for(Iterator iter = superclass().localMethodsSignature(signature).iterator(); iter.hasNext(); ) { 384 MethodDecl m = (MethodDecl)iter.next(); 385 if(!m.isPrivate()) 386 set = set.add(m); 387 } 388 } 389 if(set.size() != 1 || ((MethodDecl)set.iterator().next()).isAbstract()) { 390 for(Iterator iter = interfacesMethodsSignature(signature).iterator(); iter.hasNext(); ) { 391 MethodDecl m = (MethodDecl)iter.next(); 392 set = set.add(m); 393 } 394 } 395 if(!hasSuperclass()) return set; 396 if(set.size() == 1) { 397 MethodDecl m = (MethodDecl)set.iterator().next(); 398 if(!m.isAbstract()) { 399 boolean done = true; 400 for(Iterator iter = superclass().ancestorMethods(signature).iterator(); iter.hasNext(); ) { 401 MethodDecl n = (MethodDecl)iter.next(); 402 if(n.isPrivate() || !n.accessibleFrom(m.hostType())) 403 done = false; 404 } 405 if(done) return set; 406 } 407 } 408 for(Iterator iter = superclass().ancestorMethods(signature).iterator(); iter.hasNext(); ) { 409 MethodDecl m = (MethodDecl)iter.next(); 410 set = set.add(m); 411 } 412 return set; 413 } 414 eq InterfaceDecl.ancestorMethods(String signature) { 415 SimpleSet set = SimpleSet.emptySet; 416 for(Iterator outerIter = superinterfacesIterator(); outerIter.hasNext(); ) { 417 TypeDecl typeDecl = (TypeDecl)outerIter.next(); 418 for(Iterator iter = typeDecl.methodsSignature(signature).iterator(); iter.hasNext(); ) { 419 MethodDecl m = (MethodDecl)iter.next(); 420 set = set.add(m); 421 } 422 } 423 if(!superinterfacesIterator().hasNext()) { 424 for(Iterator iter = typeObject().methodsSignature(signature).iterator(); iter.hasNext(); ) { 425 MethodDecl m = (MethodDecl)iter.next(); 426 if(m.isPublic()) 427 set = set.add(m); 428 } 429 } 430 return set; 431 } 432 }