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