1 /*
   2  * Copyright (c) 1994, 2006, 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 }