|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
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; |
|
|
|
|
|
|
|
*/ |
|
public ClassDeclaration(Identifier name) { |
|
this.type = Type.tClass(name); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public int getStatus() { |
|
return status; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public Identifier getName() { |
|
return type.getClassName(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public Type getType() { |
|
return type; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public boolean isDefined() { |
|
switch (status) { |
|
case CS_BINARY: |
|
case CS_PARSED: |
|
case CS_CHECKED: |
|
case CS_COMPILED: |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public ClassDefinition getClassDefinition() { |
|
return definition; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private boolean found = false; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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 |
|
|
|
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 |
|
|
|
if (!definition.isInsideLocal()) { |
|
// Classes inside a block, including anonymous classes, |
|
|
|
definition.basicCheck(env); |
|
} |
|
|
|
found = true; |
|
return definition; |
|
|
|
case CS_CHECKED: |
|
case CS_COMPILED: |
|
found = true; |
|
return definition; |
|
|
|
default: |
|
throw new ClassNotFound(getName()); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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()); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void setDefinition(ClassDefinition definition, int status) { |
|
|
|
// Sanity checks. |
|
|
|
|
|
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; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public boolean equals(Object obj) { |
|
if (obj instanceof ClassDeclaration) { |
|
return type.equals(((ClassDeclaration)obj).type); |
|
} |
|
return false; |
|
} |
|
|
|
@Override |
|
public int hashCode() { |
|
return type.hashCode(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
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; |
|
} |
|
} |