blob: b55c191f7510eebf2012db6c0a32fd1c7d05f52d [file] [log] [blame]
/*
* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.tools.java;
/**
* This class represents an Java class declaration. It refers
* to either a binary or source definition.
*
* ClassDefinitions are loaded on demand, this means that
* class declarations are late bound. The definition of the
* class is obtained in stages. The status field describes
* the state of the class definition:
*
* CS_UNDEFINED - the definition is not yet loaded
* CS_UNDECIDED - a binary definition is loaded, but it is
* still unclear if the source definition need to
* be loaded
* CS_BINARY - the binary class is loaded
* CS_PARSED - the class is loaded from the source file, the
* type information is available, but the class has
* not yet been compiled.
* CS_CHECKED - the class is loaded from the source file and has
* been type-checked.
* CS_COMPILED - the class has been type checked, compiled,
* and written out.
* CS_NOTFOUND - no class definition could be found
*
* WARNING: The contents of this source file are not part of any
* supported API. Code that depends on them does so at its own risk:
* they are subject to change or removal without notice.
*/
public final
class ClassDeclaration implements Constants {
int status;
Type type;
ClassDefinition definition;
/**
* Constructor
*/
public ClassDeclaration(Identifier name) {
this.type = Type.tClass(name);
}
/**
* Get the status of the class
*/
public int getStatus() {
return status;
}
/**
* Get the name of the class
*/
public Identifier getName() {
return type.getClassName();
}
/**
* Get the type of the class
*/
public Type getType() {
return type;
}
/**
* Check if the class is defined
*/
public boolean isDefined() {
switch (status) {
case CS_BINARY:
case CS_PARSED:
case CS_CHECKED:
case CS_COMPILED:
return true;
}
return false;
}
/**
* Get the definition of this class. Returns null if
* the class is not yet defined.
*/
public ClassDefinition getClassDefinition() {
return definition;
}
/**
* This is a flag for use by getClassDefinition(env). It is
* used to mark that a class has been successfully looked up
* by that method before.
*/
private boolean found = false;
/**
* Get the definition of this class, if the class is not
* yet defined, load the definition. Loading a class may
* throw various exceptions.
*/
public ClassDefinition getClassDefinition(Environment env)
throws ClassNotFound {
if (tracing) env.dtEvent("getClassDefinition: " +
getName() + ", status " + getStatus());
// The majority of calls to getClassDefinition() are duplicates.
// This check makes them fast. It also allows us to avoid
// duplicate, useless calls to basicCheck(). In the future it
// would be good to add an additional status value, CS_BASICCHECKED.
if (found) {
return definition;
}
for(;;) {
switch (status) {
case CS_UNDEFINED:
case CS_UNDECIDED:
case CS_SOURCE:
env.loadDefinition(this);
break;
case CS_BINARY:
case CS_PARSED:
//+FIX FOR BUGID 4056065
//definition.basicCheck(env);
if (!definition.isInsideLocal()) {
// Classes inside a block, including anonymous classes,
// are checked when their surrounding member is checked.
definition.basicCheck(env);
}
//-FIX FOR BUGID 4056065
found = true;
return definition;
case CS_CHECKED:
case CS_COMPILED:
found = true;
return definition;
default:
throw new ClassNotFound(getName());
}
}
}
/**
* Get the definition of this class, if the class is not
* yet defined, load the definition. Loading a class may
* throw various exceptions. Perform no basicCheck() on this
* class.
*/
public ClassDefinition getClassDefinitionNoCheck(Environment env) throws ClassNotFound {
if (tracing) env.dtEvent("getClassDefinition: " +
getName() + ", status " + getStatus());
for(;;) {
switch (status) {
case CS_UNDEFINED:
case CS_UNDECIDED:
case CS_SOURCE:
env.loadDefinition(this);
break;
case CS_BINARY:
case CS_PARSED:
case CS_CHECKED:
case CS_COMPILED:
return definition;
default:
throw new ClassNotFound(getName());
}
}
}
/**
* Set the class definition
*/
public void setDefinition(ClassDefinition definition, int status) {
// Sanity checks.
// The name of the definition should match that of the declaration.
if ((definition != null) && !getName().equals(definition.getName())) {
throw new CompilerError("setDefinition: name mismatch: " +
this + ", " + definition);
}
// The status states can be considered ordered in the same
// manner as their numerical values. We expect classes to
// progress through a sequence of monotonically increasing
// states. NOTE: There are currently exceptions to this rule
// which are believed to be legitimate. In particular, a
// class may be checked more than once, though we believe that
// this is unnecessary and may be avoided.
/*-----------------*
if (status <= this.status) {
System.out.println("STATUS REGRESSION: " +
this + " FROM " + this.status + " TO " + status);
}
*------------------*/
this.definition = definition;
this.status = status;
}
/**
* Equality
*/
public boolean equals(Object obj) {
if (obj instanceof ClassDeclaration) {
return type.equals(((ClassDeclaration)obj).type);
}
return false;
}
@Override
public int hashCode() {
return type.hashCode();
}
/**
* toString
*/
public String toString() {
String name = getName().toString();
String type = "type ";
String nested = getName().isInner() ? "nested " : "";
if (getClassDefinition() != null) {
if (getClassDefinition().isInterface()) {
type = "interface ";
} else {
type = "class ";
}
if (!getClassDefinition().isTopLevel()) {
nested = "inner ";
if (getClassDefinition().isLocal()) {
nested = "local ";
if (!getClassDefinition().isAnonymous()) {
name = getClassDefinition().getLocalName() +
" (" + name + ")";
}
}
}
}
return nested + type + name;
}
}