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 InnerClasses { 011 // no attribute since needed in phases when the AST has been modified 012 public boolean TypeDecl.hasField(String name) { 013 if(!memberFields(name).isEmpty()) 014 return true; 015 for(int i = 0; i < getNumBodyDecl(); i++) { 016 if(getBodyDecl(i) instanceof FieldDeclaration) { 017 FieldDeclaration decl = (FieldDeclaration)getBodyDecl(i); 018 if(decl.name().equals(name)) 019 return true; 020 } 021 } 022 return false; 023 } 024 025 private TypeDecl VarAccess.fieldQualifierType() { 026 if(hasPrevExpr()) 027 return prevExpr().type(); 028 TypeDecl typeDecl = hostType(); 029 while(typeDecl != null && !typeDecl.hasField(name())) 030 typeDecl = typeDecl.enclosingType(); 031 if(typeDecl != null) 032 return typeDecl; 033 return decl().hostType(); 034 } 035 036 public boolean TypeDecl.hasMethod(String id) { 037 if(!memberMethods(id).isEmpty()) return true; 038 for(int i = 0; i < getNumBodyDecl(); i++) { 039 if(getBodyDecl(i) instanceof MethodDecl) { 040 MethodDecl decl = (MethodDecl)getBodyDecl(i); 041 if(decl.name().equals(id)) 042 return true; 043 } 044 } 045 return false; 046 } 047 048 private TypeDecl MethodAccess.methodQualifierType() { 049 if(hasPrevExpr()) 050 return prevExpr().type(); 051 TypeDecl typeDecl = hostType(); 052 while(typeDecl != null && !typeDecl.hasMethod(name())) 053 typeDecl = typeDecl.enclosingType(); 054 if(typeDecl != null) 055 return typeDecl; 056 return decl().hostType(); 057 } 058 059 060 // Helpers for arrays 061 inh TypeDecl ArrayInit.expectedType(); 062 // eq Program.getCompilationUnit(int i).expectedType() = null; 063 // ES: switching to getChild to include compilation units moved to nta 064 eq Program.getChild(int i).expectedType() = null; 065 066 eq ArrayCreationExpr.getArrayInit().expectedType() = type().componentType(); 067 eq FieldDeclaration.getInit().expectedType() = type().componentType(); 068 eq VariableDeclaration.getInit().expectedType() = type().componentType(); 069 eq VariableDecl.getInit().expectedType() = null; 070 eq ArrayInit.getInit().expectedType() = expectedType().componentType(); 071 072 syn lazy int ArrayCreationExpr.numArrays() { 073 int i = type().dimension(); 074 Access a = getTypeAccess(); 075 while(a instanceof ArrayTypeAccess && !(a instanceof ArrayTypeWithSizeAccess)) { 076 i--; 077 a = ((ArrayTypeAccess)a).getAccess(); 078 } 079 return i; 080 } 081 082 syn TypeDecl TypeDecl.stringPromotion() = this; 083 eq ReferenceType.stringPromotion() = typeObject(); 084 eq NullType.stringPromotion() = typeObject(); 085 eq ByteType.stringPromotion() = typeInt(); 086 eq ShortType.stringPromotion() = typeInt(); 087 088 syn boolean ASTNode.isStringAdd() = false; 089 eq AddExpr.isStringAdd() = type().isString() && !isConstant(); 090 091 syn boolean AddExpr.firstStringAddPart() = type().isString() && !getLeftOperand().isStringAdd(); 092 syn boolean AddExpr.lastStringAddPart() = !getParent().isStringAdd(); 093 094 syn MethodDecl TypeDecl.methodWithArgs(String name, TypeDecl[] args) { 095 for(Iterator iter = memberMethods(name).iterator(); iter.hasNext(); ) { 096 MethodDecl m = (MethodDecl)iter.next(); 097 if(m.getNumParameter() == args.length) { 098 for(int i = 0; i < args.length; i++) 099 if(m.getParameter(i).type() == args[i]) 100 return m; 101 } 102 } 103 return null; 104 } 105 106 protected TypeDecl Access.superConstructorQualifier(TypeDecl targetEnclosingType) { 107 TypeDecl enclosing = hostType(); 108 while(!enclosing.instanceOf(targetEnclosingType)) 109 enclosing = enclosing.enclosingType(); 110 return enclosing; 111 } 112 113 public TypeDecl MethodAccess.superAccessorTarget() { 114 TypeDecl targetDecl = prevExpr().type(); 115 TypeDecl enclosing = hostType(); 116 do { 117 enclosing = enclosing.enclosingType(); 118 } while (!enclosing.instanceOf(targetDecl)); 119 return enclosing; 120 } 121 122 // The set of TypeDecls that has this TypeDecl as their directly enclosing TypeDecl. 123 // I.e., NestedTypes, InnerTypes, AnonymousClasses, LocalClasses. 124 private Collection TypeDecl.nestedTypes; 125 public Collection TypeDecl.nestedTypes() { 126 return nestedTypes != null ? nestedTypes : new HashSet(); 127 } 128 public void TypeDecl.addNestedType(TypeDecl typeDecl) { 129 if(nestedTypes == null) nestedTypes = new HashSet(); 130 if(typeDecl != this) 131 nestedTypes.add(typeDecl); 132 } 133 134 // The set of nested TypeDecls that are accessed in this TypeDecl 135 private Collection TypeDecl.usedNestedTypes; 136 public Collection TypeDecl.usedNestedTypes() { 137 return usedNestedTypes != null ? usedNestedTypes : new HashSet(); 138 } 139 public void TypeDecl.addUsedNestedType(TypeDecl typeDecl) { 140 if(usedNestedTypes == null) usedNestedTypes = new HashSet(); 141 usedNestedTypes.add(typeDecl); 142 } 143 144 // collect the set of variables used in the enclosing class(es) 145 syn lazy Collection TypeDecl.enclosingVariables() { 146 HashSet set = new HashSet(); 147 for(TypeDecl e = this; e != null; e = e.enclosingType()) 148 if(e.isLocalClass() || e.isAnonymous()) 149 collectEnclosingVariables(set, e.enclosingType()); 150 if(isClassDecl()) { 151 ClassDecl classDecl = (ClassDecl)this; 152 if(classDecl.isNestedType() && classDecl.hasSuperclass()) 153 set.addAll(classDecl.superclass().enclosingVariables()); 154 } 155 return set; 156 } 157 158 public void ASTNode.collectEnclosingVariables(HashSet set, TypeDecl typeDecl) { 159 for(int i = 0; i < getNumChild(); i++) 160 getChild(i).collectEnclosingVariables(set, typeDecl); 161 } 162 public void VarAccess.collectEnclosingVariables(HashSet set, TypeDecl typeDecl) { 163 Variable v = decl(); 164 if(!v.isInstanceVariable() && !v.isClassVariable() && v.hostType() == typeDecl) 165 set.add(v); 166 super.collectEnclosingVariables(set, typeDecl); 167 } 168 169 170 public int TypeDecl.accessorCounter = 0; 171 172 private HashMap TypeDecl.accessorMap = null; 173 public ASTNode TypeDecl.getAccessor(ASTNode source, String name) { 174 ArrayList key = new ArrayList(2); 175 key.add(source); 176 key.add(name); 177 if(accessorMap == null || !accessorMap.containsKey(key)) return null; 178 return (ASTNode)accessorMap.get(key); 179 } 180 181 public void TypeDecl.addAccessor(ASTNode source, String name, ASTNode accessor) { 182 ArrayList key = new ArrayList(2); 183 key.add(source); 184 key.add(name); 185 if(accessorMap == null) accessorMap = new HashMap(); 186 accessorMap.put(key, accessor); 187 } 188 189 public ASTNode TypeDecl.getAccessorSource(ASTNode accessor) { 190 Iterator i = accessorMap.entrySet().iterator(); 191 while (i.hasNext()) { 192 Map.Entry entry = (Map.Entry) i.next(); 193 if (entry.getValue() == accessor) 194 return (ASTNode) ((ArrayList) entry.getKey()).get(0); 195 } 196 return null; 197 } 198 199 public MethodDecl MethodDecl.createAccessor(TypeDecl methodQualifier) { 200 MethodDecl m = (MethodDecl)methodQualifier.getAccessor(this, "method"); 201 if(m != null) return m; 202 203 int accessorIndex = methodQualifier.accessorCounter++; 204 205 List parameterList = new List(); 206 for(int i = 0; i < getNumParameter(); i++) 207 parameterList.add(new ParameterDeclaration( 208 // We don't need to create a qualified access to the type here 209 // since there can be no ambiguity concerning unqualified 210 // type names in an inner/enclosing class 211 // Jesper 2012-05-04 212 // FALSE! We need to create a qualified access in case the 213 // method we are generating an access for is not declared 214 // in the methodQualifier type 215 getParameter(i).type().createQualifiedAccess(), 216 getParameter(i).name())); 217 List exceptionList = new List(); 218 for(int i = 0; i < getNumException(); i++) 219 exceptionList.add((Access) getException(i).fullCopy()); 220 221 // add synthetic flag to modifiers 222 Modifiers modifiers = new Modifiers(new List()); 223 if(getModifiers().isStatic()) 224 modifiers.addModifier(new Modifier("static")); 225 modifiers.addModifier(new Modifier("synthetic")); 226 modifiers.addModifier(new Modifier("public")); 227 // build accessor declaration 228 m = new MethodDecl( 229 modifiers, 230 getTypeAccess().type().createQualifiedAccess(), 231 name() + "$access$" + accessorIndex, 232 parameterList, 233 exceptionList, 234 new Opt( 235 new Block( 236 new List().add( 237 createAccessorStmt() 238 ) 239 ) 240 ) 241 ); 242 m = methodQualifier.addMemberMethod(m); 243 methodQualifier.addAccessor(this, "method", m); 244 return m; 245 } 246 247 private Stmt MethodDecl.createAccessorStmt() { 248 List argumentList = new List(); 249 for(int i = 0; i < getNumParameter(); i++) 250 argumentList.add(new VarAccess(getParameter(i).name())); 251 Access access = new BoundMethodAccess(name(), argumentList, this); 252 if(!isStatic()) 253 access = new ThisAccess("this").qualifiesAccess(access); 254 return isVoid() ? (Stmt) new ExprStmt(access) : new ReturnStmt(new Opt(access)); 255 } 256 257 public MethodDecl MethodDecl.createSuperAccessor(TypeDecl methodQualifier) { 258 MethodDecl m = (MethodDecl)methodQualifier.getAccessor(this, "method_super"); 259 if(m != null) return m; 260 261 int accessorIndex = methodQualifier.accessorCounter++; 262 List parameters = new List(); 263 List args = new List(); 264 for(int i = 0; i < getNumParameter(); i++) { 265 parameters.add(new ParameterDeclaration(getParameter(i).type(), getParameter(i).name())); 266 args.add(new VarAccess(getParameter(i).name())); 267 } 268 Stmt stmt; 269 if(type().isVoid()) 270 stmt = new ExprStmt(new SuperAccess("super").qualifiesAccess(new MethodAccess(name(), args))); 271 else 272 stmt = new ReturnStmt(new Opt(new SuperAccess("super").qualifiesAccess(new MethodAccess(name(), args)))); 273 m = new MethodDecl( 274 new Modifiers(new List().add(new Modifier("synthetic"))), 275 type().createQualifiedAccess(), 276 name() + "$access$" + accessorIndex, 277 parameters, 278 new List(), 279 new Opt( 280 new Block( 281 new List().add(stmt) 282 ) 283 ) 284 ); 285 m = methodQualifier.addMemberMethod(m); 286 methodQualifier.addAccessor(this, "method_super", m); 287 return m; 288 } 289 290 public MethodDecl FieldDeclaration.createAccessor(TypeDecl fieldQualifier) { 291 MethodDecl m = (MethodDecl)fieldQualifier.getAccessor(this, "field_read"); 292 if(m != null) return m; 293 294 int accessorIndex = fieldQualifier.accessorCounter++; 295 Modifiers modifiers = new Modifiers(new List()); 296 modifiers.addModifier(new Modifier("static")); 297 modifiers.addModifier(new Modifier("synthetic")); 298 modifiers.addModifier(new Modifier("public")); 299 300 List parameters = new List(); 301 if(!isStatic()) 302 parameters.add(new ParameterDeclaration(fieldQualifier.createQualifiedAccess(), "that")); 303 304 m = new MethodDecl( 305 modifiers, 306 type().createQualifiedAccess(), 307 "get$" + name() + "$access$" + accessorIndex, 308 parameters, 309 new List(), 310 new Opt( 311 new Block( 312 new List().add( 313 new ReturnStmt(createAccess()) 314 ) 315 ) 316 ) 317 ); 318 m = fieldQualifier.addMemberMethod(m); 319 fieldQualifier.addAccessor(this, "field_read", m); 320 return m; 321 } 322 323 public MethodDecl FieldDeclaration.createAccessorWrite(TypeDecl fieldQualifier) { 324 MethodDecl m = (MethodDecl)fieldQualifier.getAccessor(this, "field_write"); 325 if(m != null) return m; 326 327 int accessorIndex = fieldQualifier.accessorCounter++; 328 Modifiers modifiers = new Modifiers(new List()); 329 modifiers.addModifier(new Modifier("static")); 330 modifiers.addModifier(new Modifier("synthetic")); 331 modifiers.addModifier(new Modifier("public")); 332 333 List parameters = new List(); 334 if(!isStatic()) 335 parameters.add(new ParameterDeclaration(fieldQualifier.createQualifiedAccess(), "that")); 336 parameters.add(new ParameterDeclaration(type().createQualifiedAccess(), "value")); 337 338 m = new MethodDecl( 339 modifiers, 340 type().createQualifiedAccess(), 341 "set$" + name() + "$access$" + accessorIndex, 342 parameters, 343 new List(), 344 new Opt( 345 new Block( 346 new List().add( 347 new ExprStmt( 348 new AssignSimpleExpr( 349 createAccess(), 350 new VarAccess("value") 351 ) 352 ) 353 ).add( 354 new ReturnStmt( 355 new Opt( 356 new VarAccess("value") 357 ) 358 ) 359 ) 360 ) 361 ) 362 ); 363 m = fieldQualifier.addMemberMethod(m); 364 fieldQualifier.addAccessor(this, "field_write", m); 365 return m; 366 } 367 368 private Access FieldDeclaration.createAccess() { 369 Access fieldAccess = new BoundFieldAccess(this); 370 return isStatic() ? fieldAccess : new VarAccess("that").qualifiesAccess(fieldAccess); 371 } 372 373 syn boolean VarAccess.requiresAccessor() { 374 Variable v = decl(); 375 if(!(v instanceof FieldDeclaration)) 376 return false; 377 FieldDeclaration f = (FieldDeclaration)v; 378 if(f.isPrivate() && !hostType().hasField(v.name())) 379 return true; 380 if(f.isProtected() && !f.hostPackage().equals(hostPackage()) && !hostType().hasField(v.name())) 381 return true; 382 return false; 383 } 384 385 syn boolean MethodAccess.requiresAccessor() { 386 MethodDecl m = decl(); 387 if(m.isPrivate() && m.hostType() != hostType()) 388 return true; 389 if(m.isProtected() && !m.hostPackage().equals(hostPackage()) && !hostType().hasMethod(m.name())) 390 return true; 391 return false; 392 } 393 394 syn boolean TypeDecl.isAnonymousInNonStaticContext() { 395 return isAnonymous() && 396 !((ClassInstanceExpr)getParent().getParent()).unqualifiedScope().inStaticContext() 397 && (!inExplicitConstructorInvocation() || enclosingBodyDecl().hostType().isInnerType()); 398 } 399 400 syn boolean TypeDecl.needsEnclosing() { 401 if(isAnonymous()) 402 return isAnonymousInNonStaticContext(); 403 else if(isLocalClass()) 404 return !inStaticContext(); 405 else if(isInnerType()) 406 return true; 407 return false; 408 } 409 410 syn boolean TypeDecl.needsSuperEnclosing() { 411 if(!isAnonymous()) 412 return false; 413 TypeDecl superClass = ((ClassDecl)this).superclass(); 414 if(superClass.isLocalClass()) 415 return !superClass.inStaticContext(); 416 else if(superClass.isInnerType()) 417 return true; 418 if(needsEnclosing() && enclosing() == superEnclosing()) 419 return false; 420 return false; 421 } 422 syn TypeDecl TypeDecl.enclosing() { 423 if(!needsEnclosing()) 424 return null; 425 TypeDecl typeDecl = enclosingType(); 426 if(isAnonymous() && inExplicitConstructorInvocation()) 427 typeDecl = typeDecl.enclosingType(); 428 return typeDecl; 429 } 430 syn TypeDecl TypeDecl.superEnclosing() = null; 431 eq ClassDecl.superEnclosing() = superclass().enclosing(); 432 433 syn boolean ConstructorDecl.needsEnclosing() = hostType().needsEnclosing(); 434 syn boolean ConstructorDecl.needsSuperEnclosing() = hostType().needsSuperEnclosing(); 435 436 syn TypeDecl ConstructorDecl.enclosing() = hostType().enclosing(); 437 syn TypeDecl ConstructorDecl.superEnclosing() = hostType().superEnclosing(); 438 439 440 441 // add val$name as fields to the class 442 private boolean TypeDecl.addEnclosingVariables = true; 443 public void TypeDecl.addEnclosingVariables() { 444 if(!addEnclosingVariables) return; 445 addEnclosingVariables = false; 446 for(Iterator iter = enclosingVariables().iterator(); iter.hasNext(); ) { 447 Variable v = (Variable)iter.next(); 448 Modifiers m = new Modifiers(); 449 m.addModifier(new Modifier("public")); 450 m.addModifier(new Modifier("synthetic")); 451 m.addModifier(new Modifier("final")); 452 addMemberField(new FieldDeclaration(m, v.type().createQualifiedAccess(), "val$" + v.name(), new Opt())); 453 } 454 } 455 456 // add val$name as parameters to the constructor 457 protected boolean ConstructorDecl.addEnclosingVariables = true; 458 public void ConstructorDecl.addEnclosingVariables() { 459 if(!addEnclosingVariables) return; 460 addEnclosingVariables = false; 461 hostType().addEnclosingVariables(); 462 for(Iterator iter = hostType().enclosingVariables().iterator(); iter.hasNext(); ) { 463 Variable v = (Variable)iter.next(); 464 getParameterList().add(new ParameterDeclaration(v.type(), "val$" + v.name())); 465 } 466 } 467 468 // add val$name as arguments to the constructor 469 protected boolean ConstructorAccess.addEnclosingVariables = true; 470 public void ConstructorAccess.addEnclosingVariables() { 471 if(!addEnclosingVariables) return; 472 addEnclosingVariables = false; 473 decl().addEnclosingVariables(); 474 for(Iterator iter = decl().hostType().enclosingVariables().iterator(); iter.hasNext(); ) { 475 Variable v = (Variable)iter.next(); 476 getArgList().add(new VarAccess("val$" + v.name())); 477 } 478 } 479 480 // add val$name as arguments to the constructor 481 protected boolean ClassInstanceExpr.addEnclosingVariables = true; 482 public void ClassInstanceExpr.addEnclosingVariables() { 483 if(!addEnclosingVariables) return; 484 addEnclosingVariables = false; 485 decl().addEnclosingVariables(); 486 for(Iterator iter = decl().hostType().enclosingVariables().iterator(); iter.hasNext(); ) { 487 Variable v = (Variable)iter.next(); 488 getArgList().add(new VarAccess(v.name())); 489 } 490 } 491 492 public ConstructorDecl ConstructorDecl.createAccessor() { 493 ConstructorDecl c = (ConstructorDecl)hostType().getAccessor(this, "constructor"); 494 if(c != null) return c; 495 496 // make sure enclosing varibles are added as parameters prior to building accessor 497 addEnclosingVariables(); 498 499 Modifiers modifiers = new Modifiers(new List()); 500 modifiers.addModifier(new Modifier("synthetic")); 501 modifiers.addModifier(new Modifier("public")); 502 503 List parameters = createAccessorParameters(); 504 505 List exceptionList = new List(); 506 for(int i = 0; i < getNumException(); i++) 507 exceptionList.add(getException(i).type().createQualifiedAccess()); 508 509 // add all parameters as arguments except for the dummy parameter 510 List args = new List(); 511 for(int i = 0; i < parameters.getNumChildNoTransform() - 1; i++) 512 args.add(new VarAccess(((ParameterDeclaration)parameters.getChildNoTransform(i)).name())); 513 ConstructorAccess access = new ConstructorAccess("this", args); 514 access.addEnclosingVariables = false; 515 516 c = new ConstructorDecl( 517 modifiers, 518 name(), 519 parameters, 520 exceptionList, 521 new Opt( 522 new ExprStmt( 523 access 524 ) 525 ), 526 new Block( 527 new List().add(new ReturnStmt(new Opt())) 528 ) 529 ); 530 c = hostType().addConstructor(c); 531 c.addEnclosingVariables = false; 532 hostType().addAccessor(this, "constructor", c); 533 return c; 534 } 535 536 protected List ConstructorDecl.createAccessorParameters() { 537 List parameters = new List(); 538 for (int i=0; i<getNumParameter(); i++) 539 parameters.add(new ParameterDeclaration(getParameter(i).type(), getParameter(i).name())); 540 parameters.add(new ParameterDeclaration(createAnonymousJavaTypeDecl().createBoundAccess(), ("p" + getNumParameter()))); 541 return parameters; 542 } 543 544 protected TypeDecl ConstructorDecl.createAnonymousJavaTypeDecl() { 545 ClassDecl classDecl = 546 new ClassDecl( 547 new Modifiers(new List().add(new Modifier("synthetic"))), 548 "" + hostType().nextAnonymousIndex(), 549 new Opt(), 550 new List(), 551 new List() 552 ); 553 classDecl = hostType().addMemberClass(classDecl); 554 hostType().addNestedType(classDecl); 555 return classDecl; 556 } 557 558 }