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.java;
  27 
  28 /**
  29  * This class represents an Java class declaration. It refers
  30  * to either a binary or source definition.
  31  *
  32  * ClassDefinitions are loaded on demand, this means that
  33  * class declarations are late bound. The definition of the
  34  * class is obtained in stages. The status field describes
  35  * the state of the class definition:
  36  *
  37  * CS_UNDEFINED - the definition is not yet loaded
  38  * CS_UNDECIDED - a binary definition is loaded, but it is
  39  *                still unclear if the source definition need to
  40  *                be loaded
  41  * CS_BINARY    - the binary class is loaded
  42  * CS_PARSED    - the class is loaded from the source file, the
  43  *                type information is available, but the class has
  44  *                not yet been compiled.
  45  * CS_CHECKED   - the class is loaded from the source file and has
  46  *                been type-checked.
  47  * CS_COMPILED  - the class has been type checked, compiled,
  48  *                and written out.
  49  * CS_NOTFOUND  - no class definition could be found
  50  *
  51  * WARNING: The contents of this source file are not part of any
  52  * supported API.  Code that depends on them does so at its own risk:
  53  * they are subject to change or removal without notice.
  54  */
  55 
  56 public final
  57 class ClassDeclaration implements Constants {
  58     int status;
  59     Type type;
  60     ClassDefinition definition;
  61 
  62     /**
  63      * Constructor
  64      */
  65     public ClassDeclaration(Identifier name) {
  66         this.type = Type.tClass(name);
  67     }
  68 
  69     /**
  70      * Get the status of the class
  71      */
  72     public int getStatus() {
  73         return status;
  74     }
  75 
  76     /**
  77      * Get the name of the class
  78      */
  79     public Identifier getName() {
  80        return type.getClassName();
  81     }
  82 
  83     /**
  84      * Get the type of the class
  85      */
  86     public Type getType() {
  87         return type;
  88     }
  89 
  90     /**
  91      * Check if the class is defined
  92      */
  93     public boolean isDefined() {
  94         switch (status) {
  95           case CS_BINARY:
  96           case CS_PARSED:
  97           case CS_CHECKED:
  98           case CS_COMPILED:
  99             return true;
 100         }
 101         return false;
 102     }
 103 
 104     /**
 105      * Get the definition of this class. Returns null if
 106      * the class is not yet defined.
 107      */
 108     public ClassDefinition getClassDefinition() {
 109         return definition;
 110     }
 111 
 112     /**
 113      * This is a flag for use by getClassDefinition(env).  It is
 114      * used to mark that a class has been successfully looked up
 115      * by that method before.
 116      */
 117     private boolean found = false;
 118 
 119     /**
 120      * Get the definition of this class, if the class is not
 121      * yet defined, load the definition. Loading a class may
 122      * throw various exceptions.
 123      */
 124     public ClassDefinition getClassDefinition(Environment env)
 125     throws ClassNotFound {
 126         if (tracing) env.dtEvent("getClassDefinition: " +
 127                                  getName() + ", status " + getStatus());
 128 
 129         // The majority of calls to getClassDefinition() are duplicates.
 130         // This check makes them fast.  It also allows us to avoid
 131         // duplicate, useless calls to basicCheck().  In the future it
 132         // would be good to add an additional status value, CS_BASICCHECKED.
 133         if (found) {
 134             return definition;
 135         }
 136 
 137         for(;;) {
 138             switch (status) {
 139                 case CS_UNDEFINED:
 140                 case CS_UNDECIDED:
 141                 case CS_SOURCE:
 142                     env.loadDefinition(this);
 143                     break;
 144 
 145                 case CS_BINARY:
 146                 case CS_PARSED:
 147                     //+FIX FOR BUGID 4056065
 148                     //definition.basicCheck(env);
 149                     if (!definition.isInsideLocal()) {
 150                         // Classes inside a block, including anonymous classes,
 151                         // are checked when their surrounding member is checked.
 152                         definition.basicCheck(env);
 153                     }
 154                     //-FIX FOR BUGID 4056065
 155                     found = true;
 156                     return definition;
 157 
 158                 case CS_CHECKED:
 159                 case CS_COMPILED:
 160                     found = true;
 161                     return definition;
 162 
 163                 default:
 164                     throw new ClassNotFound(getName());
 165                 }
 166         }
 167     }
 168 
 169     /**
 170      * Get the definition of this class, if the class is not
 171      * yet defined, load the definition. Loading a class may
 172      * throw various exceptions.  Perform no basicCheck() on this
 173      * class.
 174      */
 175     public ClassDefinition getClassDefinitionNoCheck(Environment env) throws ClassNotFound {
 176         if (tracing) env.dtEvent("getClassDefinition: " +
 177                                  getName() + ", status " + getStatus());
 178         for(;;) {
 179             switch (status) {
 180                 case CS_UNDEFINED:
 181                 case CS_UNDECIDED:
 182                 case CS_SOURCE:
 183                     env.loadDefinition(this);
 184                     break;
 185 
 186                 case CS_BINARY:
 187                 case CS_PARSED:
 188                 case CS_CHECKED:
 189                 case CS_COMPILED:
 190                     return definition;
 191 
 192                 default:
 193                     throw new ClassNotFound(getName());
 194                 }
 195         }
 196     }
 197 
 198    /**
 199      * Set the class definition
 200      */
 201     public void setDefinition(ClassDefinition definition, int status) {
 202 
 203         // Sanity checks.
 204 
 205         // The name of the definition should match that of the declaration.
 206         if ((definition != null) && !getName().equals(definition.getName())) {
 207             throw new CompilerError("setDefinition: name mismatch: " +
 208                                     this + ", " + definition);
 209         }
 210 
 211         // The status states can be considered ordered in the same
 212         // manner as their numerical values. We expect classes to
 213         // progress through a sequence of monotonically increasing
 214         // states. NOTE: There are currently exceptions to this rule
 215         // which are believed to be legitimate.  In particular, a
 216         // class may be checked more than once, though we believe that
 217         // this is unnecessary and may be avoided.
 218         /*-----------------*
 219         if (status <= this.status) {
 220             System.out.println("STATUS REGRESSION: " +
 221                                this + " FROM " + this.status + " TO " + status);
 222         }
 223         *------------------*/
 224 
 225         this.definition = definition;
 226         this.status = status;
 227     }
 228 
 229     /**
 230      * Equality
 231      */
 232     public boolean equals(Object obj) {
 233         if ((obj != null) && (obj instanceof ClassDeclaration)) {
 234             return type.equals(((ClassDeclaration)obj).type);
 235         }
 236         return false;
 237     }
 238 
 239     @Override
 240     public int hashCode() {
 241         return type.hashCode();
 242     }
 243 
 244     /**
 245      * toString
 246      */
 247     public String toString() {
 248         String name = getName().toString();
 249         String type = "type ";
 250         String nested = getName().isInner() ? "nested " : "";
 251         if (getClassDefinition() != null) {
 252             if (getClassDefinition().isInterface()) {
 253                 type = "interface ";
 254             } else {
 255                 type = "class ";
 256             }
 257             if (!getClassDefinition().isTopLevel()) {
 258                 nested = "inner ";
 259                 if (getClassDefinition().isLocal()) {
 260                     nested = "local ";
 261                     if (!getClassDefinition().isAnonymous()) {
 262                         name = getClassDefinition().getLocalName() +
 263                             " (" + name + ")";
 264                     }
 265                 }
 266             }
 267         }
 268         return nested + type + name;
 269     }
 270 }