1/*
2 * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package 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
56public final
57class 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 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}
271