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