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    }