View Javadoc
1   /*
2    * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package sun.tools.java;
27  
28  import sun.tools.tree.Node;
29  import sun.tools.tree.Vset;
30  import sun.tools.tree.Expression;
31  import sun.tools.tree.Statement;
32  import sun.tools.tree.Context;
33  import sun.tools.asm.Assembler;
34  import java.io.PrintStream;
35  import java.util.Vector;
36  import java.util.Map;
37  import java.util.HashMap;
38  
39  /**
40   * This class defines a member of a Java class:
41   * a variable, a method, or an inner class.
42   *
43   * WARNING: The contents of this source file are not part of any
44   * supported API.  Code that depends on them does so at its own risk:
45   * they are subject to change or removal without notice.
46   */
47  public
48  class MemberDefinition implements Constants {
49      protected long where;
50      protected int modifiers;
51      protected Type type;
52      protected String documentation;
53      protected IdentifierToken expIds[];
54      protected ClassDeclaration exp[];
55      protected Node value;
56      protected ClassDefinition clazz;
57      protected Identifier name;
58      protected ClassDefinition innerClass;
59      protected MemberDefinition nextMember;
60      protected MemberDefinition nextMatch;
61      protected MemberDefinition accessPeer;
62      protected boolean superAccessMethod;
63  
64      /**
65       * Constructor
66       */
67      public MemberDefinition(long where, ClassDefinition clazz, int modifiers,
68                              Type type, Identifier name,
69                              IdentifierToken expIds[], Node value) {
70          if (expIds == null) {
71              expIds = new IdentifierToken[0];
72          }
73          this.where = where;
74          this.clazz = clazz;
75          this.modifiers = modifiers;
76          this.type = type;
77          this.name = name;
78          this.expIds = expIds;
79          this.value = value;
80      }
81  
82      /**
83       * Constructor for an inner class.
84       * Inner classes are represented as fields right along with
85       * variables and methods for simplicity of data structure,
86       * and to reflect properly the textual declaration order.
87       * <p>
88       * This constructor calls the generic constructor for this
89       * class, extracting all necessary values from the innerClass.
90       */
91      public MemberDefinition(ClassDefinition innerClass) {
92          this(innerClass.getWhere(),
93               innerClass.getOuterClass(),
94               innerClass.getModifiers(),
95               innerClass.getType(),
96               innerClass.getName().getFlatName().getName(),
97               null, null);
98          this.innerClass = innerClass;
99      }
100 
101     /**
102      * A cache of previously created proxy members.  Used to ensure
103      * uniqueness of proxy objects.  See the makeProxyMember method
104      * defined below.
105      */
106     static private Map proxyCache;
107 
108     /**
109      * Create a member which is externally the same as `field' but
110      * is defined in class `classDef'.  This is used by code
111      * in sun.tools.tree.(MethodExpression,FieldExpression) as
112      * part of the fix for bug 4135692.
113      *
114      * Proxy members should not be added, ala addMember(), to classes.
115      * They are merely "stand-ins" to produce modified MethodRef
116      * constant pool entries during code generation.
117      *
118      * We keep a cache of previously created proxy members not to
119      * save time or space, but to ensure uniqueness of the proxy
120      * member for any (field,classDef) pair.  If these are not made
121      * unique then we can end up generating duplicate MethodRef
122      * constant pool entries during code generation.
123      */
124     public static MemberDefinition makeProxyMember(MemberDefinition field,
125                                                    ClassDefinition classDef,
126                                                    Environment env) {
127 
128         if (proxyCache == null) {
129             proxyCache = new HashMap();
130         }
131 
132         String key = field.toString() + "@" + classDef.toString();
133         // System.out.println("Key is : " + key);
134         MemberDefinition proxy = (MemberDefinition)proxyCache.get(key);
135 
136         if (proxy != null)
137             return proxy;
138 
139         proxy = new MemberDefinition(field.getWhere(), classDef,
140                                      field.getModifiers(), field.getType(),
141                                      field.getName(), field.getExceptionIds(),
142                                      null);
143         proxy.exp = field.getExceptions(env);
144         proxyCache.put(key, proxy);
145 
146         return proxy;
147     }
148 
149     /**
150      * Get the position in the input
151      */
152     public final long getWhere() {
153         return where;
154     }
155 
156     /**
157      * Get the class declaration
158      */
159     public final ClassDeclaration getClassDeclaration() {
160         return clazz.getClassDeclaration();
161     }
162 
163     /**
164      * A stub.  Subclasses can do more checking.
165      */
166     public void resolveTypeStructure(Environment env) {
167     }
168 
169     /**
170      * Get the class declaration in which the field is actually defined
171      */
172     public ClassDeclaration getDefiningClassDeclaration() {
173         return getClassDeclaration();
174     }
175 
176     /**
177      * Get the class definition
178      */
179     public final ClassDefinition getClassDefinition() {
180         return clazz;
181     }
182 
183     /**
184      * Get the field's top-level enclosing class
185      */
186     public final ClassDefinition getTopClass() {
187         return clazz.getTopClass();
188     }
189 
190     /**
191      * Get the field's modifiers
192      */
193     public final int getModifiers() {
194         return modifiers;
195     }
196     public final void subModifiers(int mod) {
197         modifiers &= ~mod;
198     }
199     public final void addModifiers(int mod) {
200         modifiers |= mod;
201     }
202 
203     /**
204      * Get the field's type
205      */
206     public final Type getType() {
207         return type;
208     }
209 
210     /**
211      * Get the field's name
212      */
213     public final Identifier getName() {
214         return name;
215     }
216 
217     /**
218      * Get arguments (a vector of LocalMember)
219      */
220     public Vector getArguments() {
221         return isMethod() ? new Vector() : null;
222     }
223 
224     /**
225      * Get the exceptions that are thrown by this method.
226      */
227     public ClassDeclaration[] getExceptions(Environment env) {
228         if (expIds != null && exp == null) {
229             if (expIds.length == 0)
230                 exp = new ClassDeclaration[0];
231             else
232                 // we should have translated this already!
233                 throw new CompilerError("getExceptions "+this);
234         }
235         return exp;
236     }
237 
238     public final IdentifierToken[] getExceptionIds() {
239         return expIds;
240     }
241 
242     /**
243      * Get an inner class.
244      */
245     public ClassDefinition getInnerClass() {
246         return innerClass;
247     }
248 
249     /**
250      * Is this a synthetic field which holds a copy of,
251      * or reference to, a local variable or enclosing instance?
252      */
253     public boolean isUplevelValue() {
254         if (!isSynthetic() || !isVariable() || isStatic()) {
255             return false;
256         }
257         String name = this.name.toString();
258         return name.startsWith(prefixVal)
259             || name.startsWith(prefixLoc)
260             || name.startsWith(prefixThis);
261     }
262 
263     public boolean isAccessMethod() {
264         // This no longer works, because access methods
265         // for constructors do not use the standard naming
266         // scheme.
267         //    return isSynthetic() && isMethod()
268         //        && name.toString().startsWith(prefixAccess);
269         // Assume that a method is an access method if it has
270         // an access peer.  NOTE: An access method will not be
271         // recognized as such until 'setAccessMethodTarget' has
272         // been called on it.
273         return isSynthetic() && isMethod() && (accessPeer != null);
274     }
275 
276     /**
277      * Is this a synthetic method which provides access to a
278      * visible private member?
279      */
280     public MemberDefinition getAccessMethodTarget() {
281         if (isAccessMethod()) {
282             for (MemberDefinition f = accessPeer; f != null; f = f.accessPeer) {
283                 // perhaps skip over another access for the same field
284                 if (!f.isAccessMethod()) {
285                     return f;
286                 }
287             }
288         }
289         return null;
290     }
291 
292 
293     public void setAccessMethodTarget(MemberDefinition target) {
294         if (getAccessMethodTarget() != target) {
295             /*-------------------*
296             if (!isAccessMethod() || accessPeer != null ||
297                     target.accessPeer != null) {
298                 throw new CompilerError("accessPeer");
299             }
300             *-------------------*/
301             if (accessPeer != null || target.accessPeer != null) {
302                 throw new CompilerError("accessPeer");
303             }
304             accessPeer = target;
305         }
306     }
307 
308     /**
309      * If this method is a getter for a private field, return the setter.
310      */
311     public MemberDefinition getAccessUpdateMember() {
312         if (isAccessMethod()) {
313             for (MemberDefinition f = accessPeer; f != null; f = f.accessPeer) {
314                 if (f.isAccessMethod()) {
315                     return f;
316                 }
317             }
318         }
319         return null;
320     }
321 
322     public void setAccessUpdateMember(MemberDefinition updater) {
323         if (getAccessUpdateMember() != updater) {
324             if (!isAccessMethod() ||
325                     updater.getAccessMethodTarget() != getAccessMethodTarget()) {
326                 throw new CompilerError("accessPeer");
327             }
328             updater.accessPeer = accessPeer;
329             accessPeer = updater;
330         }
331     }
332 
333     /**
334      * Is this an access method for a field selection or method call
335      * of the form '...super.foo' or '...super.foo()'?
336      */
337     public final boolean isSuperAccessMethod() {
338         return superAccessMethod;
339     }
340 
341     /**
342      * Mark this member as an access method for a field selection
343      * or method call via the 'super' keyword.
344      */
345     public final void setIsSuperAccessMethod(boolean b) {
346         superAccessMethod = b;
347     }
348 
349     /**
350      * Tell if this is a final variable without an initializer.
351      * Such variables are subject to definite single assignment.
352      */
353     public final boolean isBlankFinal() {
354         return isFinal() && !isSynthetic() && getValue() == null;
355     }
356 
357     public boolean isNeverNull() {
358         if (isUplevelValue()) {
359             // loc$x and this$C are never null
360             return !name.toString().startsWith(prefixVal);
361         }
362         return false;
363     }
364 
365     /**
366      * Get the field's final value (may return null)
367      */
368     public Node getValue(Environment env) throws ClassNotFound {
369         return value;
370     }
371     public final Node getValue() {
372         return value;
373     }
374     public final void setValue(Node value) {
375         this.value = value;
376     }
377     public Object getInitialValue() {
378         return null;
379     }
380 
381     /**
382      * Get the next field or the next match
383      */
384     public final MemberDefinition getNextMember() {
385         return nextMember;
386     }
387     public final MemberDefinition getNextMatch() {
388         return nextMatch;
389     }
390 
391     /**
392      * Get the field's documentation
393      */
394     public String getDocumentation() {
395         return documentation;
396     }
397 
398     /**
399      * Request a check of the field definition.
400      */
401     public void check(Environment env) throws ClassNotFound {
402     }
403 
404     /**
405      * Really check the field definition.
406      */
407     public Vset check(Environment env, Context ctx, Vset vset) throws ClassNotFound {
408         return vset;
409     }
410 
411     /**
412      * Generate code
413      */
414     public void code(Environment env, Assembler asm) throws ClassNotFound {
415         throw new CompilerError("code");
416     }
417     public void codeInit(Environment env, Context ctx, Assembler asm) throws ClassNotFound {
418         throw new CompilerError("codeInit");
419     }
420 
421     /**
422      * Tells whether to report a deprecation error for this field.
423      */
424     public boolean reportDeprecated(Environment env) {
425         return (isDeprecated() || clazz.reportDeprecated(env));
426     }
427 
428     /**
429      * Check if a field can reach another field (only considers
430      * forward references, not the access modifiers).
431      */
432     public final boolean canReach(Environment env, MemberDefinition f) {
433         if (f.isLocal() || !f.isVariable() || !(isVariable() || isInitializer()))
434             return true;
435         if ((getClassDeclaration().equals(f.getClassDeclaration())) &&
436             (isStatic() == f.isStatic())) {
437             // They are located in the same class, and are either both
438             // static or both non-static.  Check the initialization order.
439             while (((f = f.getNextMember()) != null) && (f != this));
440             return f != null;
441         }
442         return true;
443     }
444 
445     //-----------------------------------------------------------------
446     // The code in this section is intended to test certain kinds of
447     // compatibility between methods.  There are two kinds of compatibility
448     // that the compiler may need to test.  The first is whether one
449     // method can legally override another.  The second is whether two
450     // method definitions can legally coexist.  We use the word `meet'
451     // to mean the intersection of two legally coexisting methods.
452     // For more information on these kinds of compatibility, see the
453     // comments/code for checkOverride() and checkMeet() below.
454 
455     /**
456      * Constants used by getAccessLevel() to represent the access
457      * modifiers as numbers.
458      */
459     static final int PUBLIC_ACCESS = 1;
460     static final int PROTECTED_ACCESS = 2;
461     static final int PACKAGE_ACCESS = 3;
462     static final int PRIVATE_ACCESS = 4;
463 
464     /**
465      * Return the access modifier of this member as a number.  The idea
466      * is that this number may be used to check properties like "the
467      * access modifier of x is more restrictive than the access
468      * modifier of y" with a simple inequality test:
469      * "x.getAccessLevel() > y.getAccessLevel.
470      *
471      * This is an internal utility method.
472      */
473     private int getAccessLevel() {
474         // Could just compute this once instead of recomputing.
475         // Check to see if this is worth it.
476         if (isPublic()) {
477             return PUBLIC_ACCESS;
478         } else if (isProtected()) {
479             return PROTECTED_ACCESS;
480         } else if (isPackagePrivate()) {
481             return PACKAGE_ACCESS;
482         } else if (isPrivate()) {
483             return PRIVATE_ACCESS;
484         } else {
485             throw new CompilerError("getAccessLevel()");
486         }
487     }
488 
489     /**
490      * Munge our error message to report whether the override conflict
491      * came from an inherited method or a declared method.
492      */
493     private void reportError(Environment env, String errorString,
494                              ClassDeclaration clazz,
495                              MemberDefinition method) {
496 
497         if (clazz == null) {
498             // For example:
499             // "Instance method BLAH inherited from CLASSBLAH1 cannot be
500             //  overridden by the static method declared in CLASSBLAH2."
501             env.error(getWhere(), errorString,
502                       this, getClassDeclaration(),
503                       method.getClassDeclaration());
504         } else {
505             // For example:
506             // "In CLASSBLAH1, instance method BLAH inherited from CLASSBLAH2
507             //  cannot be overridden by the static method inherited from
508             //  CLASSBLAH3."
509             env.error(clazz.getClassDefinition().getWhere(),
510                       //"inherit." + errorString,
511                       errorString,
512                       //clazz,
513                       this, getClassDeclaration(),
514                       method.getClassDeclaration());
515         }
516     }
517 
518     /**
519      * Convenience method to see if two methods return the same type
520      */
521     public boolean sameReturnType(MemberDefinition method) {
522         // Make sure both are methods.
523         if (!isMethod() || !method.isMethod()) {
524             throw new CompilerError("sameReturnType: not method");
525         }
526 
527         Type myReturnType = getType().getReturnType();
528         Type yourReturnType = method.getType().getReturnType();
529 
530         return (myReturnType == yourReturnType);
531     }
532 
533     /**
534      * Check to see if `this' can override/hide `method'.  Caller is
535      * responsible for verifying that `method' has the same signature
536      * as `this'.  Caller is also responsible for verifying that
537      * `method' is visible to the class where this override is occurring.
538      * This method is called for the case when class B extends A and both
539      * A and B define some method.
540      * <pre>
541      *       A - void foo() throws e1
542      *       |
543      *       |
544      *       B - void foo() throws e2
545      * </pre>
546      */
547     public boolean checkOverride(Environment env, MemberDefinition method) {
548         return checkOverride(env, method, null);
549     }
550 
551     /**
552      * Checks whether `this' can override `method'.  It `clazz' is
553      * null, it reports the errors in the class where `this' is
554      * declared.  If `clazz' is not null, it reports the error in `clazz'.
555      */
556     private boolean checkOverride(Environment env,
557                                   MemberDefinition method,
558                                   ClassDeclaration clazz) {
559         // This section of code is largely based on section 8.4.6.3
560         // of the JLS.
561 
562         boolean success = true;
563 
564         // Sanity
565         if (!isMethod()) {
566             throw new CompilerError("checkOverride(), expected method");
567         }
568 
569         // Suppress checks for synthetic methods, as the compiler presumably
570         // knows what it is doing, e.g., access methods.
571         if (isSynthetic()) {
572             // Sanity check: We generally do not intend for one synthetic
573             // method to override another, though hiding of static members
574             // is expected.  This check may need to be changed if new uses
575             // of synthetic methods are devised.
576             //
577             // Query: this code was copied from elsewhere.  What
578             // exactly is the role of the !isStatic() in the test?
579             if (method.isFinal() ||
580                 (!method.isConstructor() &&
581                  !method.isStatic() && !isStatic())) {
582                 ////////////////////////////////////////////////////////////
583                 // NMG 2003-01-28 removed the following test because it is
584                 // invalidated by bridge methods inserted by the "generic"
585                 // (1.5) Java compiler.  In 1.5, this code is used,
586                 // indirectly, by rmic
587                 ////////////////////////////////////////////////////////////
588                 // throw new CompilerError("checkOverride() synthetic");
589                 ////////////////////////////////////////////////////////////
590             }
591 
592             // We trust the compiler.  (Ha!)  We're done checking.
593             return true;
594         }
595 
596         // Our caller should have verified that the method had the
597         // same signature.
598         if (getName() != method.getName() ||
599             !getType().equalArguments(method.getType())) {
600 
601             throw new CompilerError("checkOverride(), signature mismatch");
602         }
603 
604         // It is forbidden to `override' a static method with an instance
605         // method.
606         if (method.isStatic() && !isStatic()) {
607             reportError(env, "override.static.with.instance", clazz, method);
608             success = false;
609         }
610 
611         // It is forbidden to `hide' an instance method with a static
612         // method.
613         if (!method.isStatic() && isStatic()) {
614             reportError(env, "hide.instance.with.static", clazz, method);
615             success = false;
616         }
617 
618         // We cannot override a final method.
619         if (method.isFinal()) {
620             reportError(env, "override.final.method", clazz, method);
621             success = false;
622         }
623 
624         // Give a warning when we override a deprecated method with
625         // a non-deprecated one.
626         //
627         // We bend over backwards to suppress this warning if
628         // the `method' has not been already compiled or
629         // `this' has been already compiled.
630         if (method.reportDeprecated(env) && !isDeprecated()
631                && this instanceof sun.tools.javac.SourceMember) {
632             reportError(env, "warn.override.is.deprecated",
633                         clazz, method);
634         }
635 
636         // Visibility may not be more restrictive
637         if (getAccessLevel() > method.getAccessLevel()) {
638             reportError(env, "override.more.restrictive", clazz, method);
639             success = false;
640         }
641 
642         // Return type equality
643         if (!sameReturnType(method)) {
644             ////////////////////////////////////////////////////////////
645             // PCJ 2003-07-30 removed the following error because it is
646             // invalidated by the covariant return type feature of the
647             // 1.5 compiler.  The resulting check is now much looser
648             // than the actual 1.5 language spec, but that should be OK
649             // because this code is only still used by rmic.  See 4892308.
650             ////////////////////////////////////////////////////////////
651             // reportError(env, "override.different.return", clazz, method);
652             // success = false;
653             ////////////////////////////////////////////////////////////
654         }
655 
656         // Exception agreeement
657         if (!exceptionsFit(env, method)) {
658             reportError(env, "override.incompatible.exceptions",
659                         clazz, method);
660             success = false;
661         }
662 
663         return success;
664     }
665 
666     /**
667      * Check to see if two method definitions are compatible, that is
668      * do they have a `meet'.  The meet of two methods is essentially
669      * and `intersection' of
670      * two methods.  This method is called when some class C inherits
671      * declarations for some method foo from two parents (superclass,
672      * interfaces) but it does not, itself, have a declaration of foo.
673      * Caller is responsible for making sure that both methods are
674      * indeed visible in clazz.
675      * <pre>
676      *     A - void foo() throws e1
677      *      \
678      *       \     B void foo() throws e2
679      *        \   /
680      *         \ /
681      *          C
682      * </pre>
683      */
684     public boolean checkMeet(Environment env,
685                              MemberDefinition method,
686                              ClassDeclaration clazz) {
687         // This section of code is largely based on Section 8.4.6
688         // and 9.4.1 of the JLS.
689 
690         // Sanity
691         if (!isMethod()) {
692             throw new CompilerError("checkMeet(), expected method");
693         }
694 
695         // Check for both non-abstract.
696         if (!isAbstract() && !method.isAbstract()) {
697             throw new CompilerError("checkMeet(), no abstract method");
698         }
699 
700         // If either method is non-abstract, then we need to check that
701         // the abstract method can be properly overridden.  We call
702         // the checkOverride method to check this and generate any errors.
703         // This test must follow the previous test.
704         else if (!isAbstract()) {
705             return checkOverride(env, method, clazz);
706         } else if (!method.isAbstract()) {
707             return method.checkOverride(env, this, clazz);
708         }
709 
710         // Both methods are abstract.
711 
712         // Our caller should have verified that the method has the
713         // same signature.
714         if (getName() != method.getName() ||
715             !getType().equalArguments(method.getType())) {
716 
717             throw new CompilerError("checkMeet(), signature mismatch");
718         }
719 
720         // Check for return type equality
721         if (!sameReturnType(method)) {
722             // More args?
723             env.error(clazz.getClassDefinition().getWhere(),
724                       "meet.different.return",
725                       this, this.getClassDeclaration(),
726                       method.getClassDeclaration());
727             return false;
728         }
729 
730         // We don't have to check visibility -- there always
731         // potentially exists a meet.  Similarly with exceptions.
732 
733         // There does exist a meet.
734         return true;
735     }
736 
737     /**
738      * This method is meant to be used to determine if one of two inherited
739      * methods could override the other.  Unlike checkOverride(), failure
740      * is not an error.  This method is only meant to be called after
741      * checkMeet() has succeeded on the two methods.
742      *
743      * If you call couldOverride() without doing a checkMeet() first, then
744      * you are on your own.
745      */
746     public boolean couldOverride(Environment env,
747                                  MemberDefinition method) {
748 
749         // Sanity
750         if (!isMethod()) {
751             throw new CompilerError("coulcOverride(), expected method");
752         }
753 
754         // couldOverride() is only called with `this' and `method' both
755         // being inherited methods.  Neither of them is defined in the
756         // class which we are currently working on.  Even though an
757         // abstract method defined *in* a class can override a non-abstract
758         // method defined in a superclass, an abstract method inherited
759         // from an interface *never* can override a non-abstract method.
760         // This comment may sound odd, but that's the way inheritance is.
761         // The following check makes sure we aren't trying to override
762         // an inherited non-abstract definition with an abstract definition
763         // from an interface.
764         if (!method.isAbstract()) {
765             return false;
766         }
767 
768         // Visibility should be less restrictive
769         if (getAccessLevel() > method.getAccessLevel()) {
770             return false;
771         }
772 
773         // Exceptions
774         if (!exceptionsFit(env, method)) {
775             return false;
776         }
777 
778         // Potentially some deprecation warnings could be given here
779         // when we merge two abstract methods, one of which is deprecated.
780         // This is not currently reported.
781 
782         return true;
783     }
784 
785     /**
786      * Check to see if the exceptions of `this' fit within the
787      * exceptions of `method'.
788      */
789     private boolean exceptionsFit(Environment env,
790                                   MemberDefinition method) {
791         ClassDeclaration e1[] = getExceptions(env);        // my exceptions
792         ClassDeclaration e2[] = method.getExceptions(env); // parent's
793 
794         // This code is taken nearly verbatim from the old implementation
795         // of checkOverride() in SourceClass.
796     outer:
797         for (int i = 0 ; i < e1.length ; i++) {
798             try {
799                 ClassDefinition c1 = e1[i].getClassDefinition(env);
800                 for (int j = 0 ; j < e2.length ; j++) {
801                     if (c1.subClassOf(env, e2[j])) {
802                         continue outer;
803                     }
804                 }
805                 if (c1.subClassOf(env,
806                                   env.getClassDeclaration(idJavaLangError)))
807                     continue outer;
808                 if (c1.subClassOf(env,
809                                   env.getClassDeclaration(idJavaLangRuntimeException)))
810                     continue outer;
811 
812                 // the throws was neither something declared by a parent,
813                 // nor one of the ignorables.
814                 return false;
815 
816             } catch (ClassNotFound ee) {
817                 // We were unable to find one of the exceptions.
818                 env.error(getWhere(), "class.not.found",
819                           ee.name, method.getClassDeclaration());
820             }
821         }
822 
823         // All of the exceptions `fit'.
824         return true;
825     }
826 
827     //-----------------------------------------------------------------
828 
829     /**
830      * Checks
831      */
832     public final boolean isPublic() {
833         return (modifiers & M_PUBLIC) != 0;
834     }
835     public final boolean isPrivate() {
836         return (modifiers & M_PRIVATE) != 0;
837     }
838     public final boolean isProtected() {
839         return (modifiers & M_PROTECTED) != 0;
840     }
841     public final boolean isPackagePrivate() {
842         return (modifiers & (M_PUBLIC | M_PRIVATE | M_PROTECTED)) == 0;
843     }
844     public final boolean isFinal() {
845         return (modifiers & M_FINAL) != 0;
846     }
847     public final boolean isStatic() {
848         return (modifiers & M_STATIC) != 0;
849     }
850     public final boolean isSynchronized() {
851         return (modifiers & M_SYNCHRONIZED) != 0;
852     }
853     public final boolean isAbstract() {
854         return (modifiers & M_ABSTRACT) != 0;
855     }
856     public final boolean isNative() {
857         return (modifiers & M_NATIVE) != 0;
858     }
859     public final boolean isVolatile() {
860         return (modifiers & M_VOLATILE) != 0;
861     }
862     public final boolean isTransient() {
863         return (modifiers & M_TRANSIENT) != 0;
864     }
865     public final boolean isMethod() {
866         return type.isType(TC_METHOD);
867     }
868     public final boolean isVariable() {
869         return !type.isType(TC_METHOD) && innerClass == null;
870     }
871     public final boolean isSynthetic() {
872         return (modifiers & M_SYNTHETIC) != 0;
873     }
874     public final boolean isDeprecated() {
875         return (modifiers & M_DEPRECATED) != 0;
876     }
877     public final boolean isStrict() {
878         return (modifiers & M_STRICTFP) != 0;
879     }
880     public final boolean isInnerClass() {
881         return innerClass != null;
882     }
883     public final boolean isInitializer() {
884         return getName().equals(idClassInit);
885     }
886     public final boolean isConstructor() {
887         return getName().equals(idInit);
888     }
889     public boolean isLocal() {
890         return false;
891     }
892     public boolean isInlineable(Environment env, boolean fromFinal) throws ClassNotFound {
893         return (isStatic() || isPrivate() || isFinal() || isConstructor() || fromFinal) &&
894             !(isSynchronized() || isNative());
895     }
896 
897     /**
898      * Check if constant:  Will it inline away to a constant?
899      */
900     public boolean isConstant() {
901         if (isFinal() && isVariable() && value != null) {
902             try {
903                 // If an infinite regress requeries this name,
904                 // deny that it is a constant.
905                 modifiers &= ~M_FINAL;
906                 return ((Expression)value).isConstant();
907             } finally {
908                 modifiers |= M_FINAL;
909             }
910         }
911         return false;
912     }
913 
914     /**
915      * toString
916      */
917     public String toString() {
918         Identifier name = getClassDefinition().getName();
919         if (isInitializer()) {
920             return isStatic() ? "static {}" : "instance {}";
921         } else if (isConstructor()) {
922             StringBuffer buf = new StringBuffer();
923             buf.append(name);
924             buf.append('(');
925             Type argTypes[] = getType().getArgumentTypes();
926             for (int i = 0 ; i < argTypes.length ; i++) {
927                 if (i > 0) {
928                     buf.append(',');
929                 }
930                 buf.append(argTypes[i].toString());
931             }
932             buf.append(')');
933             return buf.toString();
934         } else if (isInnerClass()) {
935             return getInnerClass().toString();
936         }
937         return type.typeString(getName().toString());
938     }
939 
940     /**
941      * Print for debugging
942      */
943     public void print(PrintStream out) {
944         if (isPublic()) {
945             out.print("public ");
946         }
947         if (isPrivate()) {
948             out.print("private ");
949         }
950         if (isProtected()) {
951             out.print("protected ");
952         }
953         if (isFinal()) {
954             out.print("final ");
955         }
956         if (isStatic()) {
957             out.print("static ");
958         }
959         if (isSynchronized()) {
960             out.print("synchronized ");
961         }
962         if (isAbstract()) {
963             out.print("abstract ");
964         }
965         if (isNative()) {
966             out.print("native ");
967         }
968         if (isVolatile()) {
969             out.print("volatile ");
970         }
971         if (isTransient()) {
972             out.print("transient ");
973         }
974         out.println(toString() + ";");
975     }
976 
977     public void cleanup(Environment env) {
978         documentation = null;
979         if (isMethod() && value != null) {
980             int cost = 0;
981             if (isPrivate() || isInitializer()) {
982                 value = Statement.empty;
983             } else if ((cost =
984                         ((Statement)value)
985                        .costInline(Statement.MAXINLINECOST, null, null))
986                                 >= Statement.MAXINLINECOST) {
987                 // will never be inlined
988                 value = Statement.empty;
989             } else {
990                 try {
991                     if (!isInlineable(null, true)) {
992                         value = Statement.empty;
993                     }
994                 }
995                 catch (ClassNotFound ee) { }
996             }
997             if (value != Statement.empty && env.dump()) {
998                 env.output("[after cleanup of " + getName() + ", " +
999                            cost + " expression cost units remain]");
1000             }
1001         } else if (isVariable()) {
1002             if (isPrivate() || !isFinal() || type.isType(TC_ARRAY)) {
1003                 value = null;
1004             }
1005         }
1006     }
1007 }