1 /*
   2  * Copyright (c) 1994, 2004, 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.javac;
  27 
  28 import sun.tools.java.*;
  29 import sun.tools.tree.*;
  30 import sun.tools.asm.*;
  31 import java.util.Vector;
  32 import java.util.Enumeration;
  33 import java.util.Hashtable;
  34 import java.io.PrintStream;
  35 
  36 /**
  37  * A Source Member
  38  *
  39  * WARNING: The contents of this source file are not part of any
  40  * supported API.  Code that depends on them does so at its own risk:
  41  * they are subject to change or removal without notice.
  42  */
  43 @Deprecated
  44 public
  45 class SourceMember extends MemberDefinition implements Constants {
  46     /**
  47      * The argument names (if it is a method)
  48      */
  49     Vector<MemberDefinition> args;
  50 
  51     // set to the MemberDefinition in the interface if we have this field because
  52     // it has been forced on us
  53     MemberDefinition abstractSource;
  54 
  55     /**
  56      * The status of the field
  57      */
  58     int status;
  59 
  60     static final int PARSED     = 0;
  61     static final int CHECKING   = 1;
  62     static final int CHECKED    = 2;
  63     static final int INLINING   = 3;
  64     static final int INLINED    = 4;
  65     static final int ERROR      = 5;
  66 
  67     public Vector<MemberDefinition> getArguments() {
  68         return args;
  69     }
  70 
  71     /**
  72      * Constructor
  73      * @param argNames a vector of IdentifierToken
  74      */
  75     public SourceMember(long where, ClassDefinition clazz,
  76                        String doc, int modifiers, Type type,
  77                        Identifier name, Vector<MemberDefinition> argNames,
  78                        IdentifierToken exp[], Node value) {
  79         super(where, clazz, modifiers, type, name, exp, value);
  80         this.documentation = doc;
  81         this.args = argNames;   // for the moment
  82         // not until type names are resolved: createArgumentFields(argNames);
  83 
  84         if (ClassDefinition.containsDeprecated(documentation)) {
  85             this.modifiers |= M_DEPRECATED;
  86         }
  87     }
  88 
  89     void createArgumentFields(Vector<MemberDefinition> argNames) {
  90         // Create a list of arguments
  91         if (isMethod()) {
  92             args = new Vector<>();
  93 
  94             if (isConstructor() || !(isStatic() || isInitializer())) {
  95                 args.addElement(((SourceClass)clazz).getThisArgument());
  96             }
  97 
  98             if (argNames != null) {
  99                 Enumeration<MemberDefinition> e = argNames.elements();
 100                 Type argTypes[] = getType().getArgumentTypes();
 101                 for (int i = 0 ; i < argTypes.length ; i++) {
 102                     Object x = e.nextElement();
 103                     if (x instanceof LocalMember) {
 104                         // This should not happen, but it does
 105                         // in cases of vicious cyclic inheritance.
 106                         args = argNames;
 107                         return;
 108                     }
 109                     Identifier id;
 110                     int mod;
 111                     long where;
 112                     if (x instanceof Identifier) {
 113                         // allow argNames to be simple Identifiers (deprecated!)
 114                         id = (Identifier)x;
 115                         mod = 0;
 116                         where = getWhere();
 117                     } else {
 118                         IdentifierToken token = (IdentifierToken)x;
 119                         id = token.getName();
 120                         mod = token.getModifiers();
 121                         where = token.getWhere();
 122                     }
 123                     args.addElement(new LocalMember(where, clazz, mod,
 124                                                    argTypes[i], id));
 125                 }
 126             }
 127         }
 128     }
 129 
 130     // The methods addOuterThis() and addUplevelArguments() were
 131     // both originally part of a single method called addUplevelArguments()
 132     // which took a single boolean parameter describing which of the
 133     // two behaviors it wanted.
 134     //
 135     // The original addUplevelArguments() claimed to keep the arguments in
 136     // the following order:
 137     //
 138     // (1) <this> <early outer this> <uplevel arguments...> <true arguments...>
 139     //
 140     // (By <early outer this> I am referring to the clientOuterField added
 141     // to some constructors when they are created.  If an outer this is
 142     // added later, on demand, then this is mixed in with the rest of the
 143     // uplevel arguments and is added by addUplevelArguments.)
 144     //
 145     // In reality, the `args' Vector was generated in this order, but the
 146     // Type array `argTypes' was generated as:
 147     //
 148     // (2) <this> <uplevel arguments...> <early outer this> <true arguments...>
 149     //
 150     // This didn't make a difference in the common case -- that is, when
 151     // a class had an <outer.this> or <uplevel arguments...> but not both.
 152     // Both can happen in the case that a member class is declared inside
 153     // of a local class.  It seems that the calling sequences, generated
 154     // in places like NewInstanceExpression.codeCommon(), use order (2),
 155     // so I have changed the code below to stick with that order.  Since
 156     // the only time this happens is in classes which are insideLocal, no
 157     // one should be able to tell the difference between these orders.
 158     // (bug number 4085633)
 159 
 160     LocalMember outerThisArg = null;
 161 
 162     /**
 163      * Get outer instance link, or null if none.
 164      */
 165 
 166     public LocalMember getOuterThisArg() {
 167         return outerThisArg;
 168     }
 169 
 170     /**
 171      * Add the outer.this argument to the list of arguments for this
 172      * constructor.  This is called from resolveTypeStructure.  Any
 173      * additional uplevel arguments get added later by addUplevelArguments().
 174      */
 175 
 176     void addOuterThis() {
 177         UplevelReference refs = clazz.getReferences();
 178 
 179         // See if we have a client outer field.
 180         while (refs != null &&
 181                !refs.isClientOuterField()) {
 182             refs = refs.getNext();
 183         }
 184 
 185         // There is no outer this argument.  Quit.
 186         if (refs == null) {
 187             return;
 188         }
 189 
 190         // Get the old arg types.
 191         Type oldArgTypes[] = type.getArgumentTypes();
 192 
 193         // And make an array for the new ones with space for one more.
 194         Type argTypes[] = new Type[oldArgTypes.length + 1];
 195 
 196         LocalMember arg = refs.getLocalArgument();
 197         outerThisArg = arg;
 198 
 199         // args is our list of arguments.  It contains a `this', so
 200         // we insert at position 1.  The list of types does not have a
 201         // this, so we insert at position 0.
 202         args.insertElementAt(arg, 1);
 203         argTypes[0] = arg.getType();
 204 
 205         // Add on the rest of the constructor arguments.
 206         for (int i = 0; i < oldArgTypes.length; i++) {
 207             argTypes[i + 1] = oldArgTypes[i];
 208         }
 209 
 210         type = Type.tMethod(type.getReturnType(), argTypes);
 211     }
 212 
 213     /**
 214      * Prepend argument names and argument types for local variable references.
 215      * This information is never seen by the type-check phase,
 216      * but it affects code generation, which is the earliest moment
 217      * we have comprehensive information on uplevel references.
 218      * The code() methods tweaks the constructor calls, prepending
 219      * the proper values to the argument list.
 220      */
 221     void addUplevelArguments() {
 222         UplevelReference refs = clazz.getReferences();
 223         clazz.getReferencesFrozen();
 224 
 225         // Count how many uplevels we have to add.
 226         int count = 0;
 227         for (UplevelReference r = refs; r != null; r = r.getNext()) {
 228             if (!r.isClientOuterField()) {
 229                 count += 1;
 230             }
 231         }
 232 
 233         if (count == 0) {
 234             // None to add, quit.
 235             return;
 236         }
 237 
 238         // Get the old argument types.
 239         Type oldArgTypes[] = type.getArgumentTypes();
 240 
 241         // Make an array with enough room for the new.
 242         Type argTypes[] = new Type[oldArgTypes.length + count];
 243 
 244         // Add all of the late uplevel references to args and argTypes.
 245         // Note that they are `off-by-one' because of the `this'.
 246         int ins = 0;
 247         for (UplevelReference r = refs; r != null; r = r.getNext()) {
 248             if (!r.isClientOuterField()) {
 249                 LocalMember arg = r.getLocalArgument();
 250 
 251                 args.insertElementAt(arg, 1 + ins);
 252                 argTypes[ins] = arg.getType();
 253 
 254                 ins++;
 255             }
 256         }
 257 
 258         // Add the rest of the old arguments.
 259         for (int i = 0; i < oldArgTypes.length; i++) {
 260             argTypes[ins + i] = oldArgTypes[i];
 261         }
 262 
 263         type = Type.tMethod(type.getReturnType(), argTypes);
 264     }
 265 
 266     /**
 267      * Constructor for an inner class.
 268      */
 269     public SourceMember(ClassDefinition innerClass) {
 270         super(innerClass);
 271     }
 272 
 273     /**
 274      * Constructor.
 275      * Used only to generate an abstract copy of a method that a class
 276      * inherits from an interface
 277      */
 278     public SourceMember(MemberDefinition f, ClassDefinition c, Environment env) {
 279         this(f.getWhere(), c, f.getDocumentation(),
 280              f.getModifiers() | M_ABSTRACT, f.getType(), f.getName(), null,
 281              f.getExceptionIds(), null);
 282         this.args = f.getArguments();
 283         this.abstractSource = f;
 284         this.exp = f.getExceptions(env);
 285     }
 286 
 287     /**
 288      * Get exceptions
 289      */
 290     public ClassDeclaration[] getExceptions(Environment env) {
 291         if ((!isMethod()) || (exp != null)) {
 292             return exp;
 293         }
 294         if (expIds == null) {
 295             // (should not happen)
 296             exp = new ClassDeclaration[0];
 297             return exp;
 298         }
 299         // be sure to get the imports right:
 300         env = ((SourceClass)getClassDefinition()).setupEnv(env);
 301         exp = new ClassDeclaration[expIds.length];
 302         for (int i = 0; i < exp.length; i++) {
 303             Identifier e = expIds[i].getName();
 304             Identifier rexp = getClassDefinition().resolveName(env, e);
 305             exp[i] = env.getClassDeclaration(rexp);
 306         }
 307         return exp;
 308     }
 309 
 310     /**
 311      * Set array of name-resolved exceptions directly, e.g., for access methods.
 312      */
 313     public void setExceptions(ClassDeclaration[] exp) {
 314         this.exp = exp;
 315     }
 316 
 317     /**
 318      * Resolve types in a field, after parsing.
 319      * @see ClassDefinition.resolveTypeStructure
 320      */
 321 
 322     public boolean resolved = false;
 323 
 324     public void resolveTypeStructure(Environment env) {
 325         if (tracing) env.dtEnter("SourceMember.resolveTypeStructure: " + this);
 326 
 327         // A member should only be resolved once.  For a constructor, it is imperative
 328         // that 'addOuterThis' be called only once, else the outer instance argument may
 329         // be inserted into the argument list multiple times.
 330 
 331         if (resolved) {
 332             if (tracing) env.dtEvent("SourceMember.resolveTypeStructure: OK " + this);
 333             // This case shouldn't be happening.  It is the responsibility
 334             // of our callers to avoid attempting multiple resolutions of a member.
 335             // *** REMOVE FOR SHIPMENT? ***
 336             throw new CompilerError("multiple member type resolution");
 337             //return;
 338         } else {
 339             if (tracing) env.dtEvent("SourceMember.resolveTypeStructure: RESOLVING " + this);
 340             resolved = true;
 341         }
 342 
 343         super.resolveTypeStructure(env);
 344         if (isInnerClass()) {
 345             ClassDefinition nc = getInnerClass();
 346             if (nc instanceof SourceClass && !nc.isLocal()) {
 347                 ((SourceClass)nc).resolveTypeStructure(env);
 348             }
 349             type = innerClass.getType();
 350         } else {
 351             // Expand all class names in 'type', including those that are not
 352             // fully-qualified or refer to inner classes, into fully-qualified
 353             // names.  Local and anonymous classes get synthesized names here,
 354             // corresponding to the class files that will be generated.  This is
 355             // currently the only place where 'resolveNames' is used.
 356             type = env.resolveNames(getClassDefinition(), type, isSynthetic());
 357 
 358             // do the throws also:
 359             getExceptions(env);
 360 
 361             if (isMethod()) {
 362                 Vector<MemberDefinition> argNames = args; args = null;
 363                 createArgumentFields(argNames);
 364                 // Add outer instance argument for constructors.
 365                 if (isConstructor()) {
 366                     addOuterThis();
 367                 }
 368             }
 369         }
 370         if (tracing) env.dtExit("SourceMember.resolveTypeStructure: " + this);
 371     }
 372 
 373     /**
 374      * Get the class declaration in which the field is actually defined
 375      */
 376     public ClassDeclaration getDefiningClassDeclaration() {
 377         if (abstractSource == null)
 378             return super.getDefiningClassDeclaration();
 379         else
 380             return abstractSource.getDefiningClassDeclaration();
 381     }
 382 
 383     /**
 384      * A source field never reports deprecation, since the compiler
 385      * allows access to deprecated features that are being compiled
 386      * in the same job.
 387      */
 388     public boolean reportDeprecated(Environment env) {
 389         return false;
 390     }
 391 
 392     /**
 393      * Check this field.
 394      * <p>
 395      * This is the method which requests checking.
 396      * The real work is done by
 397      * <tt>Vset check(Environment, Context, Vset)</tt>.
 398      */
 399     public void check(Environment env) throws ClassNotFound {
 400         if (tracing) env.dtEnter("SourceMember.check: " +
 401                                  getName() + ", status = " + status);
 402         // rely on the class to check all fields in the proper order
 403         if (status == PARSED) {
 404             if (isSynthetic() && getValue() == null) {
 405                 // break a big cycle for small synthetic variables
 406                 status = CHECKED;
 407                 if (tracing)
 408                     env.dtExit("SourceMember.check: BREAKING CYCLE");
 409                 return;
 410             }
 411             if (tracing) env.dtEvent("SourceMember.check: CHECKING CLASS");
 412             clazz.check(env);
 413             if (status == PARSED) {
 414                 if (getClassDefinition().getError()) {
 415                     status = ERROR;
 416                 } else {
 417                     if (tracing)
 418                         env.dtExit("SourceMember.check: CHECK FAILED");
 419                     throw new CompilerError("check failed");
 420                 }
 421             }
 422         }
 423         if (tracing) env.dtExit("SourceMember.check: DONE " +
 424                                 getName() + ", status = " + status);
 425     }
 426 
 427     /**
 428      * Check a field.
 429      * @param vset tells which uplevel variables are definitely assigned
 430      * The vset is also used to track the initialization of blank finals
 431      * by whichever fields which are relevant to them.
 432      */
 433     public Vset check(Environment env, Context ctx, Vset vset) throws ClassNotFound {
 434         if (tracing) env.dtEvent("SourceMember.check: MEMBER " +
 435                                  getName() + ", status = " + status);
 436         if (status == PARSED) {
 437             if (isInnerClass()) {
 438                 // some classes are checked separately
 439                 ClassDefinition nc = getInnerClass();
 440                 if (nc instanceof SourceClass && !nc.isLocal()
 441                     && nc.isInsideLocal()) {
 442                     status = CHECKING;
 443                     vset = ((SourceClass)nc).checkInsideClass(env, ctx, vset);
 444                 }
 445                 status = CHECKED;
 446                 return vset;
 447             }
 448             if (env.dump()) {
 449                 System.out.println("[check field " + getClassDeclaration().getName() + "." + getName() + "]");
 450                 if (getValue() != null) {
 451                     getValue().print(System.out);
 452                     System.out.println();
 453                 }
 454             }
 455             env = new Environment(env, this);
 456 
 457             // This is where all checking of names appearing within the type
 458             // of the member is done.  Includes return type and argument types.
 459             // Since only one location ('where') for error messages is provided,
 460             // localization of errors is poor.  Throws clauses are handled below.
 461             env.resolve(where, getClassDefinition(), getType());
 462 
 463             // Make sure that all the classes that we claim to throw really
 464             // are subclasses of Throwable, and are classes that we can reach
 465             if (isMethod()) {
 466                 ClassDeclaration throwable =
 467                     env.getClassDeclaration(idJavaLangThrowable);
 468                 ClassDeclaration exp[] = getExceptions(env);
 469                 for (int i = 0 ; i < exp.length ; i++) {
 470                     ClassDefinition def;
 471                     long where = getWhere();
 472                     if (expIds != null && i < expIds.length) {
 473                         where = IdentifierToken.getWhere(expIds[i], where);
 474                     }
 475                     try {
 476                         def = exp[i].getClassDefinition(env);
 477 
 478                         // Validate access for all inner-class components
 479                         // of a qualified name, not just the last one, which
 480                         // is checked below.  Yes, this is a dirty hack...
 481                         // Part of fix for 4094658.
 482                         env.resolveByName(where, getClassDefinition(), def.getName());
 483 
 484                     } catch (ClassNotFound e) {
 485                         env.error(where, "class.not.found", e.name, "throws");
 486                         break;
 487                     }
 488                     def.noteUsedBy(getClassDefinition(), where, env);
 489                     if (!getClassDefinition().
 490                           canAccess(env, def.getClassDeclaration())) {
 491                         env.error(where, "cant.access.class", def);
 492                     } else if (!def.subClassOf(env, throwable)) {
 493                         env.error(where, "throws.not.throwable", def);
 494                     }
 495                 }
 496             }
 497 
 498             status = CHECKING;
 499 
 500             if (isMethod() && args != null) {
 501                 int length = args.size();
 502             outer_loop:
 503                 for (int i = 0; i < length; i++) {
 504                     LocalMember lf = (LocalMember)(args.elementAt(i));
 505                     Identifier name_i = lf.getName();
 506                     for (int j = i + 1; j < length; j++) {
 507                         LocalMember lf2 = (LocalMember)(args.elementAt(j));
 508                         Identifier name_j = lf2.getName();
 509                         if (name_i.equals(name_j)) {
 510                             env.error(lf2.getWhere(), "duplicate.argument",
 511                                       name_i);
 512                             break outer_loop;
 513                         }
 514                     }
 515                 }
 516             }
 517 
 518             if (getValue() != null) {
 519                 ctx = new Context(ctx, this);
 520 
 521                 if (isMethod()) {
 522                     Statement s = (Statement)getValue();
 523                     // initialize vset, indication that each of the arguments
 524                     // to the function has a value
 525 
 526                     for (Enumeration<MemberDefinition> e = args.elements(); e.hasMoreElements();){
 527                         LocalMember f = (LocalMember)e.nextElement();
 528                         vset.addVar(ctx.declare(env, f));
 529                     }
 530 
 531                     if (isConstructor()) {
 532                         // Undefine "this" in some constructors, until after
 533                         // the super constructor has been called.
 534                         vset.clearVar(ctx.getThisNumber());
 535 
 536                         // If the first thing in the definition isn't a call
 537                         // to either super() or this(), then insert one.
 538                         Expression supCall = s.firstConstructor();
 539                         if ((supCall == null)
 540                             && (getClassDefinition().getSuperClass() != null)) {
 541                             supCall = getDefaultSuperCall(env);
 542                             Statement scs = new ExpressionStatement(where,
 543                                                                     supCall);
 544                             s = Statement.insertStatement(scs, s);
 545                             setValue(s);
 546                         }
 547                     }
 548 
 549                     //System.out.println("VSET = " + vset);
 550                     ClassDeclaration exp[] = getExceptions(env);
 551                     int htsize = (exp.length > 3) ? 17 : 7;
 552                     Hashtable<Object, Object> thrown = new Hashtable<>(htsize);
 553 
 554                     vset = s.checkMethod(env, ctx, vset, thrown);
 555 
 556                     ClassDeclaration ignore1 =
 557                         env.getClassDeclaration(idJavaLangError);
 558                     ClassDeclaration ignore2 =
 559                         env.getClassDeclaration(idJavaLangRuntimeException);
 560 
 561                     for (Enumeration<Object> e = thrown.keys(); e.hasMoreElements();) {
 562                         ClassDeclaration c = (ClassDeclaration)e.nextElement();
 563                         ClassDefinition def = c.getClassDefinition(env);
 564                         if (def.subClassOf(env, ignore1)
 565                                  || def.subClassOf(env, ignore2)) {
 566                             continue;
 567                         }
 568 
 569                         boolean ok = false;
 570                         if (!isInitializer()) {
 571                             for (int i = 0 ; i < exp.length ; i++) {
 572                                 if (def.subClassOf(env, exp[i])) {
 573                                     ok = true;
 574                                 }
 575                             }
 576                         }
 577                         if (!ok) {
 578                             Node n = (Node)thrown.get(c);
 579                             long where = n.getWhere();
 580                             String errorMsg;
 581 
 582                             if (isConstructor()) {
 583                                 if (where ==
 584                                     getClassDefinition().getWhere()) {
 585 
 586                                     // If this message is being generated for
 587                                     // a default constructor, we should give
 588                                     // a different error message.  Currently
 589                                     // we check for this by seeing if the
 590                                     // constructor has the same "where" as
 591                                     // its class.  This is a bit kludgy, but
 592                                     // works. (bug id 4034836)
 593                                     errorMsg = "def.constructor.exception";
 594                                 } else {
 595                                     // Constructor with uncaught exception.
 596                                     errorMsg = "constructor.exception";
 597                                 }
 598                             } else if (isInitializer()) {
 599                                 // Initializer with uncaught exception.
 600                                 errorMsg = "initializer.exception";
 601                             } else {
 602                                 // Method with uncaught exception.
 603                                 errorMsg = "uncaught.exception";
 604                             }
 605                             env.error(where, errorMsg, c.getName());
 606                         }
 607                     }
 608                 } else {
 609                     Hashtable<Object, Object> thrown = new Hashtable<>(3);  // small & throw-away
 610                     Expression val = (Expression)getValue();
 611 
 612                     vset = val.checkInitializer(env, ctx, vset,
 613                                                 getType(), thrown);
 614                     setValue(val.convert(env, ctx, getType(), val));
 615 
 616                     // Complain about static final members of inner classes that
 617                     // do not have an initializer that is a constant expression.
 618                     // In general, static members are not permitted for inner
 619                     // classes, but an exception is made for named constants.
 620                     // Other cases of static members, including non-final ones,
 621                     // are handled in 'SourceClass'.  Part of fix for 4095568.
 622                     if (isStatic() && isFinal() && !clazz.isTopLevel()) {
 623                         if (!((Expression)getValue()).isConstant()) {
 624                             env.error(where, "static.inner.field", getName(), this);
 625                             setValue(null);
 626                         }
 627                     }
 628 
 629 
 630                     // Both RuntimeExceptions and Errors should be
 631                     // allowed in initializers.  Fix for bug 4102541.
 632                     ClassDeclaration except =
 633                          env.getClassDeclaration(idJavaLangThrowable);
 634                     ClassDeclaration ignore1 =
 635                         env.getClassDeclaration(idJavaLangError);
 636                     ClassDeclaration ignore2 =
 637                         env.getClassDeclaration(idJavaLangRuntimeException);
 638 
 639                     for (Enumeration<Object> e = thrown.keys(); e.hasMoreElements(); ) {
 640                         ClassDeclaration c = (ClassDeclaration)e.nextElement();
 641                         ClassDefinition def = c.getClassDefinition(env);
 642 
 643                         if (!def.subClassOf(env, ignore1)
 644                             && !def.subClassOf(env, ignore2)
 645                             && def.subClassOf(env, except)) {
 646                             Node n = (Node)thrown.get(c);
 647                             env.error(n.getWhere(),
 648                                       "initializer.exception", c.getName());
 649                         }
 650                     }
 651                 }
 652                 if (env.dump()) {
 653                     getValue().print(System.out);
 654                     System.out.println();
 655                 }
 656             }
 657             status = getClassDefinition().getError() ? ERROR : CHECKED;
 658         }
 659 
 660 
 661         // Initializers (static and instance) must be able to complete normally.
 662         if (isInitializer() && vset.isDeadEnd()) {
 663             env.error(where, "init.no.normal.completion");
 664             vset = vset.clearDeadEnd();
 665         }
 666 
 667         return vset;
 668     }
 669 
 670     // helper to check(): synthesize a missing super() call
 671     private Expression getDefaultSuperCall(Environment env) {
 672         Expression se = null;
 673         ClassDefinition sclass = getClassDefinition().getSuperClass().getClassDefinition();
 674         // does the superclass constructor require an enclosing instance?
 675         ClassDefinition reqc = (sclass == null) ? null
 676                              : sclass.isTopLevel() ? null
 677                              : sclass.getOuterClass();
 678         ClassDefinition thisc = getClassDefinition();
 679         if (reqc != null && !Context.outerLinkExists(env, reqc, thisc)) {
 680             se = new SuperExpression(where, new NullExpression(where));
 681             env.error(where, "no.default.outer.arg", reqc, getClassDefinition());
 682         }
 683         if (se == null) {
 684             se = new SuperExpression(where);
 685         }
 686         return new MethodExpression(where, se, idInit, new Expression[0]);
 687     }
 688 
 689     /**
 690      * Inline the field
 691      */
 692     void inline(Environment env) throws ClassNotFound {
 693         switch (status) {
 694           case PARSED:
 695             check(env);
 696             inline(env);
 697             break;
 698 
 699           case CHECKED:
 700             if (env.dump()) {
 701                 System.out.println("[inline field " + getClassDeclaration().getName() + "." + getName() + "]");
 702             }
 703             status = INLINING;
 704             env = new Environment(env, this);
 705 
 706             if (isMethod()) {
 707                 if ((!isNative()) && (!isAbstract())) {
 708                     Statement s = (Statement)getValue();
 709                     Context ctx = new Context((Context)null, this);
 710                     for (Enumeration<MemberDefinition> e = args.elements() ; e.hasMoreElements() ;) {
 711                         LocalMember local = (LocalMember)e.nextElement();
 712                         ctx.declare(env, local);
 713                     }
 714                     setValue(s.inline(env, ctx));
 715                 }
 716             } else if (isInnerClass()) {
 717                 // some classes are checked and inlined separately
 718                 ClassDefinition nc = getInnerClass();
 719                 if (nc instanceof SourceClass && !nc.isLocal()
 720                     && nc.isInsideLocal()) {
 721                     status = INLINING;
 722                     ((SourceClass)nc).inlineLocalClass(env);
 723                 }
 724                 status = INLINED;
 725                 break;
 726             } else {
 727                 if (getValue() != null)  {
 728                     Context ctx = new Context((Context)null, this);
 729                     if (!isStatic()) {
 730                         // Cf. "thisArg" in SourceClass.checkMembers().
 731                         Context ctxInst = new Context(ctx, this);
 732                         LocalMember thisArg =
 733                                     ((SourceClass)clazz).getThisArgument();
 734                         ctxInst.declare(env, thisArg);
 735                         setValue(((Expression)getValue())
 736                                     .inlineValue(env, ctxInst));
 737                     } else {
 738                         setValue(((Expression)getValue())
 739                                     .inlineValue(env, ctx));
 740                     }
 741                 }
 742             }
 743             if (env.dump()) {
 744                 System.out.println("[inlined field " + getClassDeclaration().getName() + "." + getName() + "]");
 745                 if (getValue() != null) {
 746                     getValue().print(System.out);
 747                     System.out.println();
 748                 } else {
 749                     System.out.println("<empty>");
 750                 }
 751             }
 752             status = INLINED;
 753             break;
 754         }
 755     }
 756 
 757     /**
 758      * Get the value of the field (or null if the value can't be determined)
 759      */
 760     public Node getValue(Environment env) throws ClassNotFound {
 761         Node value = getValue();
 762         if (value != null && status != INLINED) {
 763             // be sure to get the imports right:
 764             env = ((SourceClass)clazz).setupEnv(env);
 765             inline(env);
 766             value = (status == INLINED) ? getValue() : null;
 767         }
 768         return value;
 769     }
 770 
 771     public boolean isInlineable(Environment env, boolean fromFinal) throws ClassNotFound {
 772         if (super.isInlineable(env, fromFinal)) {
 773             getValue(env);
 774             return (status == INLINED) && !getClassDefinition().getError();
 775         }
 776         return false;
 777     }
 778 
 779 
 780     /**
 781      * Get the initial value of the field
 782      */
 783     public Object getInitialValue() {
 784         if (isMethod() || (getValue() == null) || (!isFinal()) || (status != INLINED)) {
 785             return null;
 786         }
 787         return ((Expression)getValue()).getValue();
 788     }
 789 
 790     /**
 791      * Generate code
 792      */
 793     public void code(Environment env, Assembler asm) throws ClassNotFound {
 794         switch (status) {
 795           case PARSED:
 796             check(env);
 797             code(env, asm);
 798             return;
 799 
 800           case CHECKED:
 801             inline(env);
 802             code(env, asm);
 803             return;
 804 
 805           case INLINED:
 806             // Actually generate code
 807             if (env.dump()) {
 808                 System.out.println("[code field " + getClassDeclaration().getName() + "." + getName() + "]");
 809             }
 810             if (isMethod() && (!isNative()) && (!isAbstract())) {
 811                 env = new Environment(env, this);
 812                 Context ctx = new Context((Context)null, this);
 813                 Statement s = (Statement)getValue();
 814 
 815                 for (Enumeration<MemberDefinition> e = args.elements() ; e.hasMoreElements() ; ) {
 816                     LocalMember f = (LocalMember)e.nextElement();
 817                     ctx.declare(env, f);
 818                     //ctx.declare(env, (LocalMember)e.nextElement());
 819                 }
 820 
 821                 /*
 822                 if (isConstructor() && ((s == null) || (s.firstConstructor() == null))) {
 823                     ClassDeclaration c = getClassDefinition().getSuperClass();
 824                     if (c != null) {
 825                         MemberDefinition field = c.getClassDefinition(env).matchMethod(env, getClassDefinition(), idInit);
 826                         asm.add(getWhere(), opc_aload, new Integer(0));
 827                         asm.add(getWhere(), opc_invokespecial, field);
 828                         asm.add(getWhere(), opc_pop);
 829                     }
 830 
 831                     // Output initialization code
 832                     for (MemberDefinition f = getClassDefinition().getFirstMember() ; f != null ; f = f.getNextMember()) {
 833                         if (!f.isStatic()) {
 834                             f.codeInit(env, ctx, asm);
 835                         }
 836                     }
 837                 }
 838                 */
 839                 if (s != null) {
 840                     s.code(env, ctx, asm);
 841                 }
 842                 if (getType().getReturnType().isType(TC_VOID) && !isInitializer()) {
 843                    asm.add(getWhere(), opc_return, true);
 844                 }
 845             }
 846             return;
 847         }
 848     }
 849 
 850     public void codeInit(Environment env, Context ctx, Assembler asm) throws ClassNotFound {
 851         if (isMethod()) {
 852             return;
 853         }
 854         switch (status) {
 855           case PARSED:
 856             check(env);
 857             codeInit(env, ctx, asm);
 858             return;
 859 
 860           case CHECKED:
 861             inline(env);
 862             codeInit(env, ctx, asm);
 863             return;
 864 
 865           case INLINED:
 866             // Actually generate code
 867             if (env.dump()) {
 868                 System.out.println("[code initializer  " + getClassDeclaration().getName() + "." + getName() + "]");
 869             }
 870             if (getValue() != null) {
 871                 Expression e = (Expression)getValue();
 872                 // The JLS Section 8.5 specifies that static (non-final)
 873                 // initializers should be executed in textual order.  Eliding
 874                 // initializations to default values can interfere with this,
 875                 // so the tests for !e.equalsDefault() have been eliminated,
 876                 // below.
 877                 if (isStatic()) {
 878                     if (getInitialValue() == null) {
 879                         // removed: && !e.equalsDefault()) {
 880                         e.codeValue(env, ctx, asm);
 881                         asm.add(getWhere(), opc_putstatic, this);
 882                     }
 883                 } else { // removed: if (!e.equalsDefault()) {
 884                     // This code doesn't appear to be reached for
 885                     // instance initializers.  Code for these is generated
 886                     // in the makeVarInits() method of the class
 887                     // MethodExpression.
 888                     asm.add(getWhere(), opc_aload, 0);
 889                     e.codeValue(env, ctx, asm);
 890                     asm.add(getWhere(), opc_putfield, this);
 891                 }
 892             }
 893             return;
 894         }
 895     }
 896 
 897     /**
 898      * Print for debugging
 899      */
 900     public void print(PrintStream out) {
 901         super.print(out);
 902         if (getValue() != null) {
 903             getValue().print(out);
 904             out.println();
 905         }
 906     }
 907 }