001 /* Copyright (c) 2005-2008, Torbjorn Ekman 002 * All rights reserved. 003 * 004 * Redistribution and use in source and binary forms, with or without 005 * modification, are permitted provided that the following conditions are met: 006 * 007 * 1. Redistributions of source code must retain the above copyright notice, 008 * this list of conditions and the following disclaimer. 009 * 010 * 2. Redistributions in binary form must reproduce the above copyright notice, 011 * this list of conditions and the following disclaimer in the documentation 012 * and/or other materials provided with the distribution. 013 * 014 * 3. Neither the name of the copyright holder nor the names of its 015 * contributors may be used to endorse or promote products derived from this 016 * software without specific prior written permission. 017 * 018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 021 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 022 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 028 * POSSIBILITY OF SUCH DAMAGE. 029 */ 030 031 aspect InnerClasses { 032 // no attribute since needed in phases when the AST has been modified 033 public boolean TypeDecl.hasField(String name) { 034 if (!memberFields(name).isEmpty()) { 035 return true; 036 } 037 for (int i = 0; i < getNumBodyDecl(); i++) { 038 if (getBodyDecl(i) instanceof FieldDeclaration) { 039 FieldDeclaration decl = (FieldDeclaration) getBodyDecl(i); 040 if (decl.name().equals(name)) { 041 return true; 042 } 043 } 044 } 045 return false; 046 } 047 048 private TypeDecl VarAccess.fieldQualifierType() { 049 if (hasPrevExpr()) { 050 return prevExpr().type(); 051 } 052 TypeDecl typeDecl = hostType(); 053 while (typeDecl != null && !typeDecl.hasField(name())) { 054 typeDecl = typeDecl.enclosingType(); 055 } 056 if (typeDecl != null) { 057 return typeDecl; 058 } 059 return decl().hostType(); 060 } 061 062 public boolean TypeDecl.hasMethod(String id) { 063 if (!memberMethods(id).isEmpty()) { 064 return true; 065 } 066 for (int i = 0; i < getNumBodyDecl(); i++) { 067 if (getBodyDecl(i) instanceof MethodDecl) { 068 MethodDecl decl = (MethodDecl) getBodyDecl(i); 069 if (decl.name().equals(id)) { 070 return true; 071 } 072 } 073 } 074 return false; 075 } 076 077 private TypeDecl MethodAccess.methodQualifierType() { 078 if (hasPrevExpr()) { 079 return prevExpr().type(); 080 } 081 TypeDecl typeDecl = hostType(); 082 while (typeDecl != null && !typeDecl.hasMethod(name())) { 083 typeDecl = typeDecl.enclosingType(); 084 } 085 if (typeDecl != null) { 086 return typeDecl; 087 } 088 return decl().hostType(); 089 } 090 091 092 // Helpers for arrays 093 inh TypeDecl ArrayInit.expectedType(); 094 095 eq Program.getChild().expectedType() = null; 096 097 eq ArrayCreationExpr.getArrayInit().expectedType() = type().componentType(); 098 eq FieldDeclaration.getInit().expectedType() = type().componentType(); 099 eq VariableDeclaration.getInit().expectedType() = type().componentType(); 100 eq VariableDecl.getInit().expectedType() = null; 101 eq ArrayInit.getInit().expectedType() = expectedType().componentType(); 102 103 syn lazy int ArrayCreationExpr.numArrays() { 104 int i = type().dimension(); 105 Access a = getTypeAccess(); 106 while (a instanceof ArrayTypeAccess && !(a instanceof ArrayTypeWithSizeAccess)) { 107 i--; 108 a = ((ArrayTypeAccess) a).getAccess(); 109 } 110 return i; 111 } 112 113 syn TypeDecl TypeDecl.stringPromotion() = this; 114 eq ReferenceType.stringPromotion() = typeObject(); 115 eq NullType.stringPromotion() = typeObject(); 116 eq ByteType.stringPromotion() = typeInt(); 117 eq ShortType.stringPromotion() = typeInt(); 118 119 syn boolean ASTNode.isStringAdd() = false; 120 eq AddExpr.isStringAdd() = type().isString() && !isConstant(); 121 122 syn boolean AddExpr.firstStringAddPart() = type().isString() && !getLeftOperand().isStringAdd(); 123 syn boolean AddExpr.lastStringAddPart() = !getParent().isStringAdd(); 124 125 syn MethodDecl TypeDecl.methodWithArgs(String name, TypeDecl[] args) { 126 for (Iterator iter = memberMethods(name).iterator(); iter.hasNext(); ) { 127 MethodDecl m = (MethodDecl) iter.next(); 128 if (m.getNumParameter() == args.length) { 129 for (int i = 0; i < args.length; i++) { 130 if (m.getParameter(i).type() == args[i]) { 131 return m; 132 } 133 } 134 } 135 } 136 return null; 137 } 138 139 protected TypeDecl Access.superConstructorQualifier(TypeDecl targetEnclosingType) { 140 TypeDecl enclosing = hostType(); 141 while (!enclosing.instanceOf(targetEnclosingType)) { 142 enclosing = enclosing.enclosingType(); 143 } 144 return enclosing; 145 } 146 147 public TypeDecl MethodAccess.superAccessorTarget() { 148 TypeDecl targetDecl = prevExpr().type(); 149 TypeDecl enclosing = hostType(); 150 do { 151 enclosing = enclosing.enclosingType(); 152 } while (!enclosing.instanceOf(targetDecl)); 153 return enclosing; 154 } 155 156 // The set of TypeDecls that has this TypeDecl as their directly enclosing TypeDecl. 157 // I.e., NestedTypes, InnerTypes, AnonymousClasses, LocalClasses. 158 public Collection<TypeDecl> TypeDecl.nestedTypes = 159 new RobustLinkedList<TypeDecl>(); 160 161 public void TypeDecl.addNestedType(TypeDecl typeDecl) { 162 if (typeDecl != this) { 163 nestedTypes.add(typeDecl); 164 } 165 } 166 167 // The set of nested TypeDecls that are accessed in this TypeDecl 168 public Collection<TypeDecl> TypeDecl.usedNestedTypes = 169 new RobustLinkedList<TypeDecl>(); 170 171 public void TypeDecl.addUsedNestedType(TypeDecl typeDecl) { 172 usedNestedTypes.add(typeDecl); 173 } 174 175 // collect the set of variables used in the enclosing class(es) 176 syn lazy Collection TypeDecl.enclosingVariables() { 177 HashSet set = new HashSet(); 178 for (TypeDecl e = this; e != null; e = e.enclosingType()) { 179 if (e.isLocalClass() || e.isAnonymous()) { 180 collectEnclosingVariables(set, e.enclosingType()); 181 } 182 } 183 if (isClassDecl()) { 184 ClassDecl classDecl = (ClassDecl) this; 185 if (classDecl.isNestedType() && classDecl.hasSuperclass()) { 186 set.addAll(classDecl.superclass().enclosingVariables()); 187 } 188 } 189 return set; 190 } 191 192 public void ASTNode.collectEnclosingVariables(HashSet set, TypeDecl typeDecl) { 193 for (int i = 0; i < getNumChild(); i++) { 194 getChild(i).collectEnclosingVariables(set, typeDecl); 195 } 196 } 197 public void VarAccess.collectEnclosingVariables(HashSet set, TypeDecl typeDecl) { 198 Variable v = decl(); 199 if (!v.isInstanceVariable() && !v.isClassVariable() && v.hostType() == typeDecl) { 200 set.add(v); 201 } 202 super.collectEnclosingVariables(set, typeDecl); 203 } 204 205 206 public int TypeDecl.accessorCounter = 0; 207 208 private HashMap TypeDecl.accessorMap = null; 209 public ASTNode TypeDecl.getAccessor(ASTNode source, String name) { 210 ArrayList key = new ArrayList(2); 211 key.add(source); 212 key.add(name); 213 if (accessorMap == null || !accessorMap.containsKey(key)) { 214 return null; 215 } 216 return (ASTNode) accessorMap.get(key); 217 } 218 219 public void TypeDecl.addAccessor(ASTNode source, String name, ASTNode accessor) { 220 ArrayList key = new ArrayList(2); 221 key.add(source); 222 key.add(name); 223 if (accessorMap == null) { 224 accessorMap = new HashMap(); 225 } 226 accessorMap.put(key, accessor); 227 } 228 229 public ASTNode TypeDecl.getAccessorSource(ASTNode accessor) { 230 Iterator i = accessorMap.entrySet().iterator(); 231 while (i.hasNext()) { 232 Map.Entry entry = (Map.Entry) i.next(); 233 if (entry.getValue() == accessor) { 234 return (ASTNode) ((ArrayList) entry.getKey()).get(0); 235 } 236 } 237 return null; 238 } 239 240 public MethodDecl MethodDecl.createAccessor(TypeDecl methodQualifier) { 241 MethodDecl m = (MethodDecl) methodQualifier.getAccessor(this, "method"); 242 if (m != null) { 243 return m; 244 } 245 246 int accessorIndex = methodQualifier.accessorCounter++; 247 248 List parameterList = new List(); 249 for (int i = 0; i < getNumParameter(); i++) { 250 parameterList.add(new ParameterDeclaration( 251 // We don't need to create a qualified access to the type here 252 // since there can be no ambiguity concerning unqualified 253 // type names in an inner/enclosing class 254 // Jesper 2012-05-04 255 // FALSE! We need to create a qualified access in case the 256 // method we are generating an access for is not declared 257 // in the methodQualifier type 258 getParameter(i).type().createQualifiedAccess(), 259 getParameter(i).name())); 260 } 261 List exceptionList = new List(); 262 for (int i = 0; i < getNumException(); i++) { 263 exceptionList.add((Access) getException(i).treeCopyNoTransform()); 264 } 265 266 // add synthetic flag to modifiers 267 Modifiers modifiers = new Modifiers(new List()); 268 if (getModifiers().isStatic()) { 269 modifiers.addModifier(new Modifier("static")); 270 } 271 modifiers.addModifier(new Modifier("synthetic")); 272 modifiers.addModifier(new Modifier("public")); 273 // build accessor declaration 274 m = new MethodDecl( 275 modifiers, 276 getTypeAccess().type().createQualifiedAccess(), 277 name() + "$access$" + accessorIndex, 278 parameterList, 279 exceptionList, 280 new Opt( 281 new Block( 282 new List().add( 283 createAccessorStmt() 284 ) 285 ) 286 ) 287 ); 288 m = methodQualifier.addMemberMethod(m); 289 methodQualifier.addAccessor(this, "method", m); 290 return m; 291 } 292 293 private Stmt MethodDecl.createAccessorStmt() { 294 List argumentList = new List(); 295 for (int i = 0; i < getNumParameter(); i++) { 296 argumentList.add(new VarAccess(getParameter(i).name())); 297 } 298 Access access = new BoundMethodAccess(name(), argumentList, this); 299 if (!isStatic()) { 300 access = new ThisAccess("this").qualifiesAccess(access); 301 } 302 return isVoid() ? (Stmt) new ExprStmt(access) : new ReturnStmt(new Opt(access)); 303 } 304 305 public MethodDecl MethodDecl.createSuperAccessor(TypeDecl methodQualifier) { 306 MethodDecl m = (MethodDecl) methodQualifier.getAccessor(this, "method_super"); 307 if (m != null) { 308 return m; 309 } 310 311 int accessorIndex = methodQualifier.accessorCounter++; 312 List parameters = new List(); 313 List args = new List(); 314 for (int i = 0; i < getNumParameter(); i++) { 315 parameters.add(new ParameterDeclaration(getParameter(i).type(), getParameter(i).name())); 316 args.add(new VarAccess(getParameter(i).name())); 317 } 318 Stmt stmt; 319 if (type().isVoid()) { 320 stmt = new ExprStmt(new SuperAccess("super").qualifiesAccess(new MethodAccess(name(), args))); 321 } else { 322 stmt = new ReturnStmt(new Opt(new SuperAccess("super").qualifiesAccess(new MethodAccess(name(), args)))); 323 } 324 m = new MethodDecl( 325 new Modifiers(new List().add(new Modifier("synthetic"))), 326 type().createQualifiedAccess(), 327 name() + "$access$" + accessorIndex, 328 parameters, 329 new List(), 330 new Opt( 331 new Block( 332 new List().add(stmt) 333 ) 334 ) 335 ); 336 m = methodQualifier.addMemberMethod(m); 337 methodQualifier.addAccessor(this, "method_super", m); 338 return m; 339 } 340 341 public MethodDecl FieldDeclaration.createAccessor(TypeDecl fieldQualifier) { 342 MethodDecl m = (MethodDecl) fieldQualifier.getAccessor(this, "field_read"); 343 if (m != null) { 344 return m; 345 } 346 347 int accessorIndex = fieldQualifier.accessorCounter++; 348 Modifiers modifiers = new Modifiers(new List()); 349 modifiers.addModifier(new Modifier("static")); 350 modifiers.addModifier(new Modifier("synthetic")); 351 modifiers.addModifier(new Modifier("public")); 352 353 List parameters = new List(); 354 if (!isStatic()) { 355 parameters.add(new ParameterDeclaration(fieldQualifier.createQualifiedAccess(), "that")); 356 } 357 358 m = new MethodDecl( 359 modifiers, 360 type().createQualifiedAccess(), 361 "get$" + name() + "$access$" + accessorIndex, 362 parameters, 363 new List(), 364 new Opt( 365 new Block( 366 new List().add( 367 new ReturnStmt(createAccess()) 368 ) 369 ) 370 ) 371 ); 372 m = fieldQualifier.addMemberMethod(m); 373 fieldQualifier.addAccessor(this, "field_read", m); 374 return m; 375 } 376 377 public MethodDecl FieldDeclaration.createAccessorWrite(TypeDecl fieldQualifier) { 378 MethodDecl m = (MethodDecl) fieldQualifier.getAccessor(this, "field_write"); 379 if (m != null) { 380 return m; 381 } 382 383 int accessorIndex = fieldQualifier.accessorCounter++; 384 Modifiers modifiers = new Modifiers(new List()); 385 modifiers.addModifier(new Modifier("static")); 386 modifiers.addModifier(new Modifier("synthetic")); 387 modifiers.addModifier(new Modifier("public")); 388 389 List parameters = new List(); 390 if (!isStatic()) { 391 parameters.add(new ParameterDeclaration(fieldQualifier.createQualifiedAccess(), "that")); 392 } 393 parameters.add(new ParameterDeclaration(type().createQualifiedAccess(), "value")); 394 395 m = new MethodDecl( 396 modifiers, 397 type().createQualifiedAccess(), 398 "set$" + name() + "$access$" + accessorIndex, 399 parameters, 400 new List(), 401 new Opt( 402 new Block( 403 new List().add( 404 new ExprStmt( 405 new AssignSimpleExpr( 406 createAccess(), 407 new VarAccess("value") 408 ) 409 ) 410 ).add( 411 new ReturnStmt( 412 new Opt( 413 new VarAccess("value") 414 ) 415 ) 416 ) 417 ) 418 ) 419 ); 420 m = fieldQualifier.addMemberMethod(m); 421 fieldQualifier.addAccessor(this, "field_write", m); 422 return m; 423 } 424 425 private Access FieldDeclaration.createAccess() { 426 Access fieldAccess = new BoundFieldAccess(this); 427 return isStatic() ? fieldAccess : new VarAccess("that").qualifiesAccess(fieldAccess); 428 } 429 430 syn boolean VarAccess.requiresAccessor() { 431 Variable v = decl(); 432 if (!(v instanceof FieldDeclaration)) { 433 return false; 434 } 435 FieldDeclaration f = (FieldDeclaration) v; 436 if (f.isPrivate() && !hostType().hasField(v.name())) { 437 return true; 438 } 439 if (f.isProtected() && !f.hostPackage().equals(hostPackage()) && !hostType().hasField(v.name())) { 440 return true; 441 } 442 return false; 443 } 444 445 syn boolean MethodAccess.requiresAccessor() { 446 MethodDecl m = decl(); 447 if (m.isPrivate() && m.hostType() != hostType()) { 448 return true; 449 } 450 if (m.isProtected() && !m.hostPackage().equals(hostPackage()) && !hostType().hasMethod(m.name())) { 451 return true; 452 } 453 return false; 454 } 455 456 syn boolean TypeDecl.isAnonymousInNonStaticContext() { 457 return isAnonymous() && 458 !((ClassInstanceExpr) getParent().getParent()).unqualifiedScope().inStaticContext() 459 && (!inExplicitConstructorInvocation() || enclosingBodyDecl().hostType().isInnerType()); 460 } 461 462 syn lazy boolean TypeDecl.needsEnclosing() { 463 if (isAnonymous()) { 464 return isAnonymousInNonStaticContext(); 465 } else if (isLocalClass()) { 466 return !inStaticContext(); 467 } else if (isInnerType()) { 468 return true; 469 } 470 return false; 471 } 472 473 syn lazy boolean TypeDecl.needsSuperEnclosing() { 474 if (!isAnonymous()) { 475 return false; 476 } 477 TypeDecl superClass = ((ClassDecl) this).superclass(); 478 if (superClass.isLocalClass()) { 479 return !superClass.inStaticContext(); 480 } else if (superClass.isInnerType()) { 481 return true; 482 } if (needsEnclosing() && enclosing() == superEnclosing()) { 483 return false; 484 } 485 return false; 486 } 487 488 syn TypeDecl TypeDecl.enclosing() { 489 if (!needsEnclosing()) { 490 return null; 491 } 492 TypeDecl typeDecl = enclosingType(); 493 if (isAnonymous() && inExplicitConstructorInvocation()) { 494 typeDecl = typeDecl.enclosingType(); 495 } 496 return typeDecl; 497 } 498 499 syn TypeDecl TypeDecl.superEnclosing() = null; 500 eq ClassDecl.superEnclosing() = superclass().enclosing(); 501 502 syn boolean ConstructorDecl.needsEnclosing() = hostType().needsEnclosing(); 503 syn boolean ConstructorDecl.needsSuperEnclosing() = hostType().needsSuperEnclosing(); 504 505 syn TypeDecl ConstructorDecl.enclosing() = hostType().enclosing(); 506 syn TypeDecl ConstructorDecl.superEnclosing() = hostType().superEnclosing(); 507 508 // add val$name as fields to the class 509 private boolean TypeDecl.addEnclosingVariables = true; 510 public void TypeDecl.addEnclosingVariables() { 511 if (!addEnclosingVariables) { 512 return; 513 } 514 addEnclosingVariables = false; 515 for (Iterator iter = enclosingVariables().iterator(); iter.hasNext(); ) { 516 Variable v = (Variable) iter.next(); 517 Modifiers m = new Modifiers(); 518 m.addModifier(new Modifier("public")); 519 m.addModifier(new Modifier("synthetic")); 520 m.addModifier(new Modifier("final")); 521 addMemberField(new FieldDeclaration(m, v.type().createQualifiedAccess(), "val$" + v.name(), new Opt())); 522 } 523 } 524 525 // add val$name as parameters to the constructor 526 protected boolean ConstructorDecl.addEnclosingVariables = true; 527 public void ConstructorDecl.addEnclosingVariables() { 528 if (!addEnclosingVariables) { 529 return; 530 } 531 addEnclosingVariables = false; 532 hostType().addEnclosingVariables(); 533 for (Iterator iter = hostType().enclosingVariables().iterator(); iter.hasNext(); ) { 534 Variable v = (Variable) iter.next(); 535 getParameterList().add(new ParameterDeclaration(v.type(), "val$" + v.name())); 536 } 537 } 538 539 // add val$name as arguments to the constructor 540 protected boolean ConstructorAccess.addEnclosingVariables = true; 541 public void ConstructorAccess.addEnclosingVariables() { 542 if (!addEnclosingVariables) { 543 return; 544 } 545 addEnclosingVariables = false; 546 decl().addEnclosingVariables(); 547 for (Iterator iter = decl().hostType().enclosingVariables().iterator(); iter.hasNext(); ) { 548 Variable v = (Variable) iter.next(); 549 getArgList().add(new VarAccess("val$" + v.name())); 550 } 551 } 552 553 // add val$name as arguments to the constructor 554 protected boolean ClassInstanceExpr.addEnclosingVariables = true; 555 public void ClassInstanceExpr.addEnclosingVariables() { 556 if (!addEnclosingVariables) { 557 return; 558 } 559 addEnclosingVariables = false; 560 decl().addEnclosingVariables(); 561 for (Iterator iter = decl().hostType().enclosingVariables().iterator(); iter.hasNext(); ) { 562 Variable v = (Variable) iter.next(); 563 getArgList().add(new VarAccess(v.name())); 564 } 565 } 566 567 public ConstructorDecl ConstructorDecl.createAccessor() { 568 ConstructorDecl c = (ConstructorDecl) hostType().getAccessor(this, "constructor"); 569 if (c != null) { 570 return c; 571 } 572 573 // make sure enclosing varibles are added as parameters prior to building accessor 574 addEnclosingVariables(); 575 576 Modifiers modifiers = new Modifiers(new List()); 577 modifiers.addModifier(new Modifier("synthetic")); 578 modifiers.addModifier(new Modifier("public")); 579 580 List parameters = createAccessorParameters(); 581 582 List exceptionList = new List(); 583 for (int i = 0; i < getNumException(); i++) { 584 exceptionList.add(getException(i).type().createQualifiedAccess()); 585 } 586 587 // add all parameters as arguments except for the dummy parameter 588 List args = new List(); 589 for (int i = 0; i < parameters.getNumChildNoTransform() - 1; i++) { 590 args.add(new VarAccess(((ParameterDeclaration) parameters.getChildNoTransform(i)).name())); 591 } 592 ConstructorAccess access = new ConstructorAccess("this", args); 593 access.addEnclosingVariables = false; 594 595 c = new ConstructorDecl( 596 modifiers, 597 name(), 598 parameters, 599 exceptionList, 600 new Opt( 601 new ExprStmt( 602 access 603 ) 604 ), 605 new Block() 606 ); 607 c = hostType().addConstructor(c); 608 c.addEnclosingVariables = false; 609 hostType().addAccessor(this, "constructor", c); 610 return c; 611 } 612 613 protected List ConstructorDecl.createAccessorParameters() { 614 List parameters = new List(); 615 for (int i=0; i<getNumParameter(); i++) { 616 parameters.add(new ParameterDeclaration(getParameter(i).type(), getParameter(i).name())); 617 } 618 parameters.add(new ParameterDeclaration(createAnonymousJavaTypeDecl().createBoundAccess(), ("p" + getNumParameter()))); 619 return parameters; 620 } 621 622 protected TypeDecl ConstructorDecl.createAnonymousJavaTypeDecl() { 623 ClassDecl classDecl = 624 new ClassDecl( 625 new Modifiers(new List().add(new Modifier("synthetic"))), 626 "" + hostType().nextAnonymousIndex(), 627 new Opt(), 628 new List(), 629 new List() 630 ); 631 classDecl = hostType().addMemberClass(classDecl); 632 hostType().addNestedType(classDecl); 633 return classDecl; 634 } 635 636 }