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 Enums { 032 033 /* 034 1) It is a compile-time error to attempt to explicitly instantiate an enum type 035 (�15.9.1). 036 */ 037 syn boolean TypeDecl.isEnumDecl() = false; 038 eq EnumDecl.isEnumDecl() = true; 039 040 refine NameCheck public void ClassInstanceExpr.nameCheck() { 041 if (getAccess().type().isEnumDecl() && !enclosingBodyDecl().isEnumConstant()) { 042 error("enum types may not be instantiated explicitly"); 043 } else { 044 refined(); 045 } 046 } 047 048 syn boolean BodyDecl.isEnumConstant() = false; 049 eq EnumConstant.isEnumConstant() = true; 050 051 /* 052 5) Enum types (�8.9) must not be declared abstract; doing so will result in a 053 compile-time error. 054 */ 055 eq EnumDecl.getModifiers().mayBeAbstract() = false; 056 057 /* 058 9) Nested enum types are implicitly static. It is permissable to explicitly 059 declare a nested enum type to be static. 060 */ 061 eq EnumDecl.isStatic() = isNestedType(); 062 eq EnumDecl.getModifiers().mayBeStatic() = isNestedType(); 063 064 /* 065 12) It is a compile-time error for an enum to declare a finalizer. An instance of 066 an enum may never be finalized. 067 */ 068 public void EnumDecl.typeCheck() { 069 super.typeCheck(); 070 for (Iterator iter = memberMethods("finalize").iterator(); iter.hasNext(); ) { 071 MethodDecl m = (MethodDecl) iter.next(); 072 if (m.getNumParameter() == 0 && m.hostType() == this) { 073 error("an enum may not declare a finalizer"); 074 } 075 } 076 checkEnum(this); 077 } 078 079 /* 080 10) The direct superclass of an enum type named E is Enum<E>. 081 */ 082 083 syn lazy Opt EnumDecl.getSuperClassOpt() { 084 return new Opt( 085 new ParTypeAccess( 086 new TypeAccess( 087 "java.lang", 088 "Enum" 089 ), 090 new List().add(createQualifiedAccess()) 091 ) 092 ); 093 } 094 095 /* 096 3b) If the enum type has no constructor declarations, a parameterless default 097 constructor is provided (which matches the implicit empty argument list). 098 This default constructor is private. 099 */ 100 101 102 eq ParameterDeclaration.getTypeAccess().nameType() = NameType.TYPE_NAME; 103 104 // TODO Remove 105 private boolean EnumDecl.done = false; 106 private boolean EnumDecl.done() { 107 if (done) { 108 return true; 109 } 110 done = true; 111 return false; 112 } 113 114 // TODO Remove 115 rewrite EnumDecl { 116 when (!done()) 117 to EnumDecl { 118 transformEnumConstructors(); 119 addValues(); // Add the values() and getValue(String s) methods 120 return this; 121 } 122 } 123 124 syn lazy Opt<ConstructorDecl> EnumDecl.getImplicitConstructorOpt() { 125 if (needsImplicitConstructor()) { 126 List parameterList = new List(); 127 parameterList.add( 128 new ParameterDeclaration(new TypeAccess("java.lang", "String"), "p0") 129 ); 130 parameterList.add( 131 new ParameterDeclaration(new TypeAccess("int"), "p1") 132 ); 133 ConstructorDecl constructor = new ConstructorDecl( 134 new Modifiers(new List() 135 .add(new Modifier("private")) 136 .add(new Modifier("synthetic")) 137 ), 138 name(), 139 parameterList, 140 new List(), 141 new Opt( 142 new ExprStmt( 143 new SuperConstructorAccess( 144 "super", 145 new List() 146 .add(new VarAccess("p0")) 147 .add(new VarAccess("p1")) 148 ) 149 ) 150 ), 151 new Block(new List()) 152 ); 153 return new Opt<ConstructorDecl>(constructor); 154 } else { 155 return new Opt<ConstructorDecl>(); 156 } 157 } 158 159 protected void ASTNode.transformEnumConstructors() { 160 for (int i = 0; i < getNumChildNoTransform(); i++) { 161 ASTNode child = getChildNoTransform(i); 162 if (child != null) { 163 child.transformEnumConstructors(); 164 } 165 } 166 } 167 168 refine LookupConstructor 169 eq ConstructorDecl.getConstructorInvocation() { 170 if (!isSynthetic() && hostType().isEnumDecl()) { 171 return getImplicitConstructorInvocation(); 172 } 173 return refined(); 174 } 175 176 refine LookupConstructor 177 eq ConstructorDecl.getImplicitConstructorInvocation() { 178 if (hostType().isEnumDecl()) { 179 ConstructorAccess newAccess; 180 if (hasParsedConstructorInvocation()) { 181 ExprStmt stmt = (ExprStmt) getParsedConstructorInvocation(); 182 ConstructorAccess access = (ConstructorAccess) stmt.getExpr(); 183 newAccess = (ConstructorAccess) access.treeCopyNoTransform(); 184 } else { 185 newAccess = new SuperConstructorAccess("super", new List()); 186 } 187 if (!hostType().original().typeName().equals("java.lang.Enum")) { 188 // java.lang.Enum calls the java.lang.Object constructor, with no extra params 189 newAccess.getArgList().insertChild(new VarAccess("@p0"),0); 190 newAccess.getArgList().insertChild(new VarAccess("@p1"),1); 191 } 192 return new ExprStmt(newAccess); 193 } 194 return refined(); 195 } 196 197 protected void ConstructorDecl.transformEnumConstructors() { 198 super.transformEnumConstructors(); 199 getParameterList().insertChild( 200 new ParameterDeclaration(new TypeAccess("java.lang", "String"), "@p0"), 201 0 202 ); 203 getParameterList().insertChild( 204 new ParameterDeclaration(new TypeAccess("int"), "@p1"), 205 1 206 ); 207 } 208 209 /* 210 11) In addition to the members it inherits from Enum<E>, for each declared 211 enum constant with the name n the enum type has an implicitly declared 212 public static final field named n of type E. These fields are considered to 213 be declared in the same order as the corresponding enum constants, before 214 any static fields explicitly declared in the enum type. Each such field is 215 initialized to the enum constant that corresponds to it. Each such field is 216 also considered to be annotated by the same annotations as the 217 corresponding enum constant. The enum constant is said to be created when 218 the corresponding field is initialized. 219 */ 220 221 eq EnumConstant.isPublic() = true; 222 eq EnumConstant.isStatic() = true; 223 eq EnumConstant.isFinal() = true; 224 225 syn lazy Access EnumConstant.getTypeAccess() { 226 return hostType().createQualifiedAccess(); 227 } 228 229 public EnumConstant.EnumConstant(Modifiers mods, String name, List<Expr> args, List<BodyDecl> bds) { 230 this(mods, name, args, new Opt<Expr>(new EnumInstanceExpr(createOptAnonymousDecl(bds)))); 231 } 232 233 /* 234 3) An enum constant may be followed by arguments, which are passed to the 235 constructor of the enum type when the constant is created during class 236 initialization as described later in this section. The constructor to be 237 invoked is chosen using the normal overloading rules (�15.12.2). If the 238 arguments are omitted, an empty argument list is assumed. 239 */ 240 241 syn lazy Access EnumInstanceExpr.getAccess() { 242 return hostType().createQualifiedAccess(); 243 } 244 245 syn lazy List<Expr> EnumInstanceExpr.getArgList() { 246 EnumConstant ec = (EnumConstant) getParent().getParent(); 247 List<EnumConstant> ecs = (List<EnumConstant>)ec.getParent(); 248 int idx = ecs.getIndexOfChild(ec); 249 if (idx == -1) { 250 throw new Error("internal: cannot determine numeric value of enum constant"); 251 } 252 List<Expr> argList = new List<Expr>(); 253 argList.add(Literal.buildStringLiteral(ec.name())); 254 argList.add(Literal.buildIntegerLiteral(idx)); 255 for (Expr arg : ec.getArgs()) { 256 argList.add((Expr) arg.treeCopyNoTransform()); 257 } 258 return argList; 259 } 260 261 /* 262 4) The optional class body of an enum constant implicitly defines an anonymous 263 class declaration (�15.9.5) that extends the immediately enclosing enum type. 264 The class body is governed by the usual rules of anonymous classes; in 265 particular it cannot contain any constructors. 266 267 TODO: work on error messages 268 */ 269 270 private static Opt<TypeDecl> EnumConstant.createOptAnonymousDecl(List<BodyDecl> bds) { 271 if (bds.getNumChildNoTransform() == 0) { 272 return new Opt<TypeDecl>(); 273 } 274 return new Opt<TypeDecl>( 275 new AnonymousDecl( 276 new Modifiers(), 277 "Anonymous", 278 bds 279 ) 280 ); 281 } 282 283 // simulate list of body declarations 284 public int EnumConstant.getNumBodyDecl() { 285 int cnt = 0; 286 ClassInstanceExpr init = (ClassInstanceExpr) getInit(); 287 if (!init.hasTypeDecl()) { 288 return 0; 289 } 290 for (BodyDecl bd : init.getTypeDecl().getBodyDecls()) { 291 if (!(bd instanceof ConstructorDecl)) { 292 ++cnt; 293 } 294 } 295 return cnt; 296 } 297 298 public BodyDecl EnumConstant.getBodyDecl(int i) { 299 ClassInstanceExpr init = (ClassInstanceExpr) getInit(); 300 if (init.hasTypeDecl()) { 301 for (BodyDecl bd : init.getTypeDecl().getBodyDecls()) { 302 if (!(bd instanceof ConstructorDecl)) { 303 if (i-- == 0) { 304 return bd; 305 } 306 } 307 } 308 } 309 throw new ArrayIndexOutOfBoundsException(i); 310 } 311 312 /* 313 7) It is a compile-time error for the class body of an enum constant to declare 314 an abstract method. 315 316 TODO: work on error messages 317 */ 318 319 /* 320 8) An enum type is implicitly final unless it contains at least one enum 321 constant that has a class body. In any case, it is a compile-time error to 322 explicitly declare an enum type to be final. 323 */ 324 325 eq EnumDecl.isFinal() { 326 for (Iterator iter = enumConstants().iterator(); iter.hasNext(); ) { 327 EnumConstant c = (EnumConstant) iter.next(); 328 ClassInstanceExpr e = (ClassInstanceExpr) c.getInit(); 329 if (e.hasTypeDecl()) { 330 return false; 331 } 332 } 333 return true; 334 } 335 eq EnumDecl.getModifiers().mayBeFinal() = false; 336 337 syn lazy ArrayList EnumDecl.enumConstants() { 338 ArrayList list = new ArrayList(); 339 for (int i = 0; i < getNumBodyDecl(); i++) { 340 if (getBodyDecl(i).isEnumConstant()) { 341 list.add(getBodyDecl(i)); 342 } 343 } 344 return list; 345 } 346 347 /* 348 13) In addition, if E is the name of an enum type, then that type has the 349 following implicitly declared static methods: 350 public static E[] values(); 351 public static E valueOf(String name); 352 */ 353 354 private void EnumDecl.addValues() { 355 int numConstants = enumConstants().size(); 356 List initValues = new List(); 357 for (Iterator iter = enumConstants().iterator(); iter.hasNext(); ) { 358 EnumConstant c = (EnumConstant) iter.next(); 359 initValues.add(c.createBoundFieldAccess()); 360 } 361 FieldDeclaration values = new FieldDeclaration( 362 new Modifiers(new List().add( 363 new Modifier("private")).add( 364 new Modifier("static")).add( 365 new Modifier("final")).add( 366 new Modifier("synthetic")) 367 ), 368 arrayType().createQualifiedAccess(), 369 "$VALUES", 370 new Opt( 371 new ArrayCreationExpr( 372 new ArrayTypeWithSizeAccess( 373 createQualifiedAccess(), 374 Literal.buildIntegerLiteral(enumConstants().size()) 375 ), 376 new Opt( 377 new ArrayInit( 378 initValues 379 ) 380 ) 381 ) 382 ) 383 ); 384 addBodyDecl(values); 385 // public static final Test[] values() { return (Test[])$VALUES.clone(); } 386 addBodyDecl( 387 new MethodDecl( 388 new Modifiers(new List().add( 389 new Modifier("public")).add( 390 new Modifier("static")).add( 391 new Modifier("final")).add( 392 new Modifier("synthetic")) 393 ), 394 arrayType().createQualifiedAccess(), 395 "values", 396 new List(), 397 new List(), 398 new Opt( 399 new Block( 400 new List().add( 401 new ReturnStmt( 402 new Opt( 403 new CastExpr( 404 arrayType().createQualifiedAccess(), 405 values.createBoundFieldAccess().qualifiesAccess( 406 new MethodAccess( 407 "clone", 408 new List() 409 ) 410 ) 411 ) 412 ) 413 ) 414 ) 415 ) 416 ) 417 ) 418 ); 419 // public static Test valueOf(String s) { return (Test) java.lang.Enum.valueOf(Test.class, s); } 420 addBodyDecl( 421 new MethodDecl( 422 new Modifiers(new List().add( 423 new Modifier("public")).add( 424 new Modifier("static")).add( 425 new Modifier("synthetic")) 426 ), 427 createQualifiedAccess(), 428 "valueOf", 429 new List().add( 430 new ParameterDeclaration( 431 new Modifiers(new List()), 432 typeString().createQualifiedAccess(), 433 "s" 434 ) 435 ), 436 new List(), 437 new Opt( 438 new Block( 439 new List().add( 440 new ReturnStmt( 441 new Opt( 442 new CastExpr( 443 createQualifiedAccess(), 444 lookupType("java.lang", "Enum").createQualifiedAccess().qualifiesAccess( 445 new MethodAccess( 446 "valueOf", 447 new List().add( 448 createQualifiedAccess().qualifiesAccess(new ClassAccess()) 449 ).add( 450 new VarAccess( 451 "s" 452 ) 453 ) 454 ) 455 ) 456 ) 457 ) 458 ) 459 ) 460 ) 461 ) 462 ) 463 ); 464 } 465 466 inh TypeDecl EnumDecl.typeString(); 467 468 /* 469 14) It is a compile-time error to reference a static field of an enum type that 470 is not a compile-time constant (�15.28) from constructors, instance 471 initializer blocks, or instance variable initializer expressions of that 472 type. 473 */ 474 475 /** 476 * @return true if the enum decl contains an abstract method declaration 477 */ 478 eq EnumDecl.isAbstract() { 479 for (int i = 0; i < getNumBodyDecl(); i++) { 480 if (getBodyDecl(i) instanceof MethodDecl) { 481 MethodDecl m = (MethodDecl) getBodyDecl(i); 482 if (m.isAbstract()) { 483 return true; 484 } 485 } 486 } 487 return false; 488 } 489 490 protected void ASTNode.checkEnum(EnumDecl enumDecl) { 491 for (int i = 0; i < getNumChild(); i++) { 492 getChild(i).checkEnum(enumDecl); 493 } 494 } 495 496 protected void EnumDecl.checkEnum(EnumDecl enumDecl) { 497 for (int i = 0; i < getNumBodyDecl(); i++) { 498 if (getBodyDecl(i) instanceof ConstructorDecl) { 499 getBodyDecl(i).checkEnum(enumDecl); 500 } else if (getBodyDecl(i) instanceof InstanceInitializer) { 501 getBodyDecl(i).checkEnum(enumDecl); 502 } else if (getBodyDecl(i) instanceof FieldDeclaration) { 503 FieldDeclaration f = (FieldDeclaration) getBodyDecl(i); 504 if (!f.isStatic() && f.hasInit()) { 505 f.checkEnum(enumDecl); 506 } 507 } 508 } 509 } 510 511 protected void TypeDecl.checkEnum(EnumDecl enumDecl) { 512 // non-EnumDecl TypeDecls should not check enum stuff 513 } 514 515 protected void VarAccess.checkEnum(EnumDecl enumDecl) { 516 super.checkEnum(enumDecl); 517 if (decl().isStatic() && decl().hostType() == enumDecl && !isConstant()) { 518 error("may not reference a static field of an enum type from here"); 519 } 520 } 521 522 /** 523 * Check if the enum constructor has an incorrect access modifier 524 */ 525 protected void ConstructorDecl.checkEnum(EnumDecl enumDecl) { 526 super.checkEnum(enumDecl); 527 528 if (isPublic()) { 529 error("enum constructors can not be declared public"); 530 } else if (isProtected()) { 531 error("enum constructors can not be declared public"); 532 } 533 534 if (hasParsedConstructorInvocation()) { 535 ExprStmt invocation = (ExprStmt) getParsedConstructorInvocation(); 536 if (invocation.getExpr() instanceof SuperConstructorAccess) { 537 error("can not call super() in enum constructor"); 538 } 539 } 540 } 541 542 /* 543 15) It is a compile-time error for the constructors, instance initializer blocks, 544 or instance variable initializer expressions of an enum constant e to refer 545 to itself or to an enum constant of the same type that is declared to the 546 right of e. 547 548 traversal that checks for errors 549 */ 550 551 552 553 // 8.9 554 555 /* 2) An enum constant may be preceded by annotation (�9.7) modifiers. If an 556 annotation a on an enum constant corresponds to an annotation type T, and T 557 has a (meta-)annotation m that corresponds to annotation.Target, then m must 558 have an element whose value is annotation.ElementType.FIELD, or a 559 compile-time error occurs. 560 Comment: This is done in Annotations.jrag 561 */ 562 563 564 eq EnumConstant.getTypeAccess().nameType() = NameType.TYPE_NAME; 565 566 refine TypeCheck public void SwitchStmt.typeCheck() { 567 TypeDecl type = getExpr().type(); 568 if ((!type.isIntegralType() || type.isLong()) && !type.isEnumDecl()) { 569 error("Switch expression must be of char, byte, short, int, or enum type"); 570 } 571 } 572 573 eq ConstCase.getValue().lookupVariable(String name) 574 = switchType().isEnumDecl() ? switchType().memberFields(name) : lookupVariable(name); 575 576 syn boolean Expr.isEnumConstant() = false; 577 eq VarAccess.isEnumConstant() = varDecl() instanceof EnumConstant; 578 579 refine TypeCheck public void ConstCase.typeCheck() { 580 boolean isEnumConstant = getValue().isEnumConstant(); 581 if (switchType().isEnumDecl() && !isEnumConstant) { 582 error("Unqualified enumeration constant required"); 583 } else { 584 TypeDecl switchType = switchType(); 585 TypeDecl type = getValue().type(); 586 if (!type.assignConversionTo(switchType, getValue())) { 587 error("Constant expression must be assignable to Expression"); 588 } 589 if (!getValue().isConstant() && !getValue().type().isUnknown() && 590 !isEnumConstant) 591 error("Switch expression must be constant"); 592 } 593 } 594 refine NameCheck eq ConstCase.constValue(Case c) { 595 if (switchType().isEnumDecl()) { 596 if (!(c instanceof ConstCase) || !getValue().isConstant()) { 597 return false; 598 } 599 return getValue().varDecl() == ((ConstCase) c).getValue().varDecl(); 600 } else { 601 return refined(c); 602 } 603 } 604 605 public void EnumDecl.prettyPrint(PrettyPrinter out) { 606 if (!docComment.isEmpty()) { 607 out.print(docComment); 608 } 609 out.print(getModifiers()); 610 out.print("enum " + name()); 611 if (getNumImplements() > 0) { 612 out.print(" implements "); 613 out.join(getImplementsList(), new PrettyPrinter.Joiner() { 614 @Override 615 public void printSeparator(PrettyPrinter out) { 616 out.print(", "); 617 } 618 }); 619 } 620 out.print(" {"); 621 for (int i = 0; i < getNumBodyDecl(); i++) { 622 BodyDecl d = getBodyDecl(i); 623 out.print(d); 624 if (d instanceof EnumConstant) { 625 if (i + 1 < getNumBodyDecl() && !(getBodyDecl(i + 1) instanceof EnumConstant)) { 626 out.println(); 627 out.print(";"); 628 } 629 } 630 } 631 out.println(); 632 out.print("}"); 633 } 634 635 public void EnumConstant.prettyPrint(PrettyPrinter out) { 636 out.println(); 637 out.print(getModifiers()); 638 out.print(getID()); 639 out.print("("); 640 if (getNumArg() > 0) { 641 out.join(getArgList(), new PrettyPrinter.Joiner() { 642 @Override 643 public void printSeparator(PrettyPrinter out) { 644 out.print(", "); 645 } 646 }); 647 } 648 out.print(")"); 649 if (getNumBodyDecl() > 0) { 650 out.print(" {"); 651 for (int i=0; i < getNumBodyDecl(); i++) { 652 BodyDecl d = getBodyDecl(i); 653 out.print(d); 654 } 655 out.print("}"); 656 } 657 out.print(","); 658 } 659 660 /** 661 * From the Java Language Specification, third edition, section 8.9 Enums: 662 * 663 * It is a compile-time error for an enum type E to have an abstract method 664 * m as a member unless E has one or more enum constants, and all of E's enum 665 * constants have class bodies that provide concrete implementations of m. 666 */ 667 eq EnumDecl.unimplementedMethods() { 668 Collection<MethodDecl> methods = new LinkedList<MethodDecl>(); 669 for (Iterator iter = interfacesMethodsIterator(); iter.hasNext(); ) { 670 MethodDecl method = (MethodDecl) iter.next(); 671 SimpleSet set = (SimpleSet) localMethodsSignature(method.signature()); 672 if (set.size() == 1) { 673 MethodDecl n = (MethodDecl) set.iterator().next(); 674 if (!n.isAbstract()) { 675 continue; 676 } 677 } 678 boolean implemented = false; 679 set = (SimpleSet) ancestorMethods(method.signature()); 680 for (Iterator i2 = set.iterator(); i2.hasNext(); ) { 681 MethodDecl n = (MethodDecl) i2.next(); 682 if (!n.isAbstract()) { 683 implemented = true; 684 break; 685 } 686 } 687 if (!implemented) { 688 methods.add(method); 689 } 690 } 691 692 for (Iterator iter = localMethodsIterator(); iter.hasNext(); ) { 693 MethodDecl method = (MethodDecl) iter.next(); 694 if (method.isAbstract()) { 695 methods.add(method); 696 } 697 } 698 699 Collection unimplemented = new ArrayList(); 700 for (MethodDecl method : methods) { 701 if (enumConstants().isEmpty()) { 702 unimplemented.add(method); 703 continue; 704 } 705 boolean missing = false; 706 for (Iterator iter = enumConstants().iterator(); iter.hasNext(); ) { 707 if (!((EnumConstant) iter.next()).implementsMethod(method)) { 708 missing = true; 709 break; 710 } 711 } 712 if (missing) { 713 unimplemented.add(method); 714 } 715 } 716 717 return unimplemented; 718 } 719 720 /** 721 * Check that the enum does not contain unimplemented abstract methods. 722 */ 723 public void EnumDecl.checkModifiers() { 724 super.checkModifiers(); 725 if (!unimplementedMethods().isEmpty()) { 726 StringBuilder sb = new StringBuilder(); 727 sb.append("" + name() + " lacks implementations in one or more " 728 + "enum constants for the following methods:\n"); 729 for (Iterator iter = unimplementedMethods().iterator(); iter.hasNext(); ) { 730 MethodDecl m = (MethodDecl) iter.next(); 731 sb.append(" " + m.signature() + " in " + m.hostType().typeName() + "\n"); 732 } 733 error(sb.toString()); 734 } 735 } 736 737 syn SimpleSet EnumConstant.localMethodsSignature(String signature) { 738 SimpleSet set = localMethodsSignatureMap().get(signature); 739 if (set != null) { 740 return set; 741 } 742 return SimpleSet.emptySet; 743 } 744 745 // signature -> method declaration 746 syn lazy Map<String,SimpleSet> EnumConstant.localMethodsSignatureMap() { 747 HashMap map = new HashMap(getNumBodyDecl()); 748 for (int i = 0; i < getNumBodyDecl(); i++) { 749 if (getBodyDecl(i) instanceof MethodDecl) { 750 MethodDecl decl = (MethodDecl) getBodyDecl(i); 751 putSimpleSetElement(map, decl.signature(), decl); 752 } 753 } 754 return map; 755 } 756 757 syn boolean EnumConstant.implementsMethod(MethodDecl method) { 758 SimpleSet set = (SimpleSet) localMethodsSignature(method.signature()); 759 if (set.size() == 1) { 760 MethodDecl n = (MethodDecl) set.iterator().next(); 761 if (!n.isAbstract()) { 762 return true; 763 } 764 } 765 return false; 766 } 767 768 refine Modifiers 769 public void MethodDecl.checkModifiers() { 770 super.checkModifiers(); 771 if (hostType().isClassDecl()) { 772 // 8.4.3.1 773 if (!hostType().isEnumDecl() && isAbstract() && !hostType().isAbstract()) { 774 error("class must be abstract to include abstract methods"); 775 } 776 // 8.4.3.1 777 if (isAbstract() && isPrivate()) { 778 error("method may not be abstract and private"); 779 } 780 // 8.4.3.1 781 // 8.4.3.2 782 if (isAbstract() && isStatic()) { 783 error("method may not be abstract and static"); 784 } 785 if (isAbstract() && isSynchronized()) { 786 error("method may not be abstract and synchronized"); 787 } 788 // 8.4.3.4 789 if (isAbstract() && isNative()) { 790 error("method may not be abstract and native"); 791 } 792 if (isAbstract() && isStrictfp()) { 793 error("method may not be abstract and strictfp"); 794 } 795 if (isNative() && isStrictfp()) { 796 error("method may not be native and strictfp"); 797 } 798 } 799 if (hostType().isInterfaceDecl()) { 800 // 9.4 801 if (isStatic()) { 802 errorf("interface method %s in %s may not be static", signature(), hostType().typeName()); 803 } 804 if (isStrictfp()) { 805 errorf("interface method %s in %s may not be strictfp", signature(), hostType().typeName()); 806 } 807 if (isNative()) { 808 errorf("interface method %s in %s may not be native", signature(), hostType().typeName()); 809 } 810 if (isSynchronized()) { 811 errorf("interface method %s in %s may not be synchronized", signature(), 812 hostType().typeName()); 813 } 814 if (isProtected()) { 815 errorf("interface method %s in %s may not be protected", signature(), 816 hostType().typeName()); 817 } 818 if (isPrivate()) { 819 errorf("interface method %s in %s may not be private", signature(), hostType().typeName()); 820 } else if (isFinal()) { 821 errorf("interface method %s in %s may not be final", signature(), hostType().typeName()); 822 } 823 } 824 } 825 }