blob: fcbbaccfd4a9322789a8e830d801b219e8e565cb [file] [log] [blame]
/*
* Copyright (c) 1998, 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.
*/
/*
* Licensed Materials - Property of IBM
* RMI-IIOP v1.0
* Copyright IBM Corp. 1998 1999 All Rights Reserved
*
*/
package sun.rmi.rmic.iiop;
import java.util.Arrays;
import java.util.Vector;
import sun.tools.java.Identifier;
import sun.tools.java.ClassNotFound;
import sun.tools.java.ClassDefinition;
import sun.tools.java.ClassDeclaration;
import sun.tools.java.MemberDefinition;
import sun.tools.java.CompilerError;
import sun.tools.tree.Node;
import sun.tools.tree.LocalMember;
import sun.tools.tree.CharExpression;
import sun.tools.tree.IntegerExpression;
import sun.rmi.rmic.IndentingWriter;
import java.io.IOException;
import java.util.HashSet;
import java.util.Enumeration;
import java.io.File;
/**
* A CompoundType is an abstract base class for all IIOP class and
* interface types.
*
* @author Bryan Atsatt
*/
public abstract class CompoundType extends Type {
protected Method[] methods;
protected InterfaceType[] interfaces;
protected Member[] members;
protected ClassDefinition classDef;
protected ClassDeclaration classDecl;
protected boolean isCORBAObject = false;
protected boolean isIDLEntity = false;
protected boolean isAbstractBase = false;
protected boolean isValueBase = false;
protected boolean isCORBAUserException = false;
protected boolean isException = false;
protected boolean isCheckedException = false;
protected boolean isRemoteExceptionOrSubclass = false;
protected String idlExceptionName;
protected String qualifiedIDLExceptionName;
//_____________________________________________________________________
// Public Interfaces
//_____________________________________________________________________
/**
* Return true if this type implements
* org.omg.CORBA.Object.
*/
public boolean isCORBAObject () {
return isCORBAObject;
}
/**
* Return true if this type implements
* org.omg.CORBA.portable.IDLEntity.
*/
public boolean isIDLEntity () {
return isIDLEntity;
}
/**
* Return true if this type implements
* org.omg.CORBA.portable.ValueBase.
*/
public boolean isValueBase () {
return isValueBase;
}
/**
* Return true if this type is a CORBA
* abstract interface.
*/
public boolean isAbstractBase () {
return isAbstractBase;
}
/**
* Return true if this type is an exception.
*/
public boolean isException () {
return isException;
}
/**
* Return true if this type is a "checked" exception.
* Result if valid iff isException() returns true.
*/
public boolean isCheckedException () {
return isCheckedException;
}
/**
* Return true if this type is a java.rmi.RemoteException
* or one of its subclasses. Result if valid iff isException()
* returns true.
*/
public boolean isRemoteExceptionOrSubclass () {
return isRemoteExceptionOrSubclass;
}
/**
* Return true if this type is exactly
* org.omg.CORBA.UserException.
*/
public boolean isCORBAUserException () {
return isCORBAUserException;
}
/**
* Return true if this type implements
* isIDLEntity() && isException().
*/
public boolean isIDLEntityException () {
return isIDLEntity() && isException();
}
/**
* Return true if isIDLEntity() && !isValueBase()
* && !isAbstractBase() && !isCORBAObject()
* && !isIDLEntityException().
*/
public boolean isBoxed () {
return (isIDLEntity() && !isValueBase() &&
!isAbstractBase() && !isCORBAObject() &&
!isIDLEntityException());
}
/**
* If this type represents an exception, return the
* IDL name including the "Ex" mangling, otherwise
* return null.
*/
public String getIDLExceptionName () {
return idlExceptionName;
}
/**
* If this type represents an exception, return the
* qualified IDL name including the "Ex" mangling,
* otherwise return null.
* @param global If true, prepends "::".
*/
public String getQualifiedIDLExceptionName (boolean global) {
if (qualifiedIDLExceptionName != null &&
global &&
getIDLModuleNames().length > 0) {
return IDL_NAME_SEPARATOR + qualifiedIDLExceptionName;
} else {
return qualifiedIDLExceptionName;
}
}
/**
* Return signature for this type (e.g. com.acme.Dynamite
* would return "com.acme.Dynamite", byte = "B")
*/
public String getSignature() {
String sig = classDecl.getType().getTypeSignature();
if (sig.endsWith(";")) {
sig = sig.substring(0,sig.length()-1);
}
return sig;
}
/**
* Return the ClassDeclaration for this type.
*/
public ClassDeclaration getClassDeclaration() {
return classDecl;
}
/**
* Return the ClassDefinition for this type.
*/
public ClassDefinition getClassDefinition() {
return classDef;
}
/**
* Return the parent class of this type. Returns null if this
* type is an interface or if there is no parent.
*/
public ClassType getSuperclass() {
return null;
}
/**
* Return an array of interfaces directly implemented by this type.
* <p>
* The order of the array returned is arbitrary.
*/
public InterfaceType[] getInterfaces() {
if( interfaces != null ) {
return (InterfaceType[]) interfaces.clone();
}
return null;
}
/**
* Return an array of Type.Method objects representing all
* of the methods implemented directly by this type.
*/
public Method[] getMethods() {
if( methods != null ) {
return (Method[]) methods.clone();
}
return null;
}
/**
* Return an array of Type.Member objects representing all of
* the data members directly implemented by this interface.
*/
public Member[] getMembers() {
if( members != null ) {
return (Member[]) members.clone();
}
return null;
}
/**
* Create a CompoundType object for the given class.
*
* If the class is not a properly formed or if some other error occurs, the
* return value will be null, and errors will have been reported to the
* supplied BatchEnvironment.
*/
public static CompoundType forCompound (ClassDefinition classDef,
ContextStack stack) {
CompoundType result = null;
try {
result = (CompoundType) makeType(classDef.getType(),classDef,stack);
} catch (ClassCastException e) {}
return result;
}
//_____________________________________________________________________
// Subclass/Internal Interfaces
//_____________________________________________________________________
/**
* Release all resources.
*/
protected void destroy () {
if (!destroyed) {
super.destroy();
if (methods != null) {
for (int i = 0; i < methods.length; i++) {
if (methods[i] != null) methods[i].destroy();
}
methods = null;
}
if (interfaces != null) {
for (int i = 0; i < interfaces.length; i++) {
if (interfaces[i] != null) interfaces[i].destroy();
}
interfaces = null;
}
if (members != null) {
for (int i = 0; i < members.length; i++) {
if (members[i] != null) members[i].destroy();
}
members = null;
}
classDef = null;
classDecl = null;
}
}
/*
* Load a Class instance. Return null if fail.
*/
protected Class loadClass() {
Class ourClass = null;
// To avoid getting out-of-date Class instances, and
// to ensure that there is an instance, we must compile
// any classes that we've seen and which are not yet
// compiled. We can't just compile this class, 'cuz it
// may have dependencies on classes which have not been
// compiled...
try {
env.getMain().compileAllClasses(env);
} catch (Exception e1) {
for (Enumeration e = env.getClasses() ; e.hasMoreElements() ; ) {
ClassDeclaration c = (ClassDeclaration)e.nextElement();
}
failedConstraint(26,false,stack,"required classes");
env.flushErrors();
}
// Now try to get the Class...
// The outer try block is there for people who might want to use
// the compiler at run-time of their AS.
// They could set and use their own context class loader for loading
// classes directly.
try {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
ourClass = cl.loadClass(getQualifiedName());
} catch(ClassNotFoundException cfe) {
try {
ourClass = env.classPathLoader.loadClass(getQualifiedName());
} catch (NullPointerException e) {
// This should never happen
} catch (ClassNotFoundException e) {
// Fall through to the next case (which is to look in the
// output directory for generated files)
}
}
/* This piece of code used to cause the compiler to ignore jar files
on its classpath
try {
ourClass = Util.loadClass(getQualifiedName(),null,null);
} catch (ClassNotFoundException e) {
} catch (LinkageError e) {
}
*/
if (ourClass == null) {
// Try one last thing. If the class was compiled into
// a directory that's not in the classpath, the load
// will fail. Let's get the bits off the disk and load
// it directly...
if (env.loader == null) {
File destDir = env.getMain().getDestinationDir();
if (destDir == null) {
destDir = new File(".");
}
env.loader = new DirectoryLoader(destDir);
}
try {
ourClass = env.loader.loadClass(getQualifiedName());
} catch (Exception e) {}
}
return ourClass;
}
// Print "extends XX"
protected boolean printExtends (IndentingWriter writer,
boolean useQualifiedNames,
boolean useIDLNames,
boolean globalIDLNames) throws IOException {
ClassType parent = getSuperclass();
if (parent != null && (!useIDLNames ||
(!parent.isType(TYPE_ANY) && !parent.isType(TYPE_CORBA_OBJECT)))) {
writer.p(" extends ");
parent.printTypeName(writer,useQualifiedNames,useIDLNames,globalIDLNames);
return true;
}
return false;
}
// Print "implements XX, YY"
protected void printImplements (IndentingWriter writer,
String prefix,
boolean useQualifiedNames,
boolean useIDLNames,
boolean globalIDLNames) throws IOException {
InterfaceType[] interfaces = getInterfaces();
String adjective = " implements";
if (isInterface()) {
adjective = " extends";
}
if (useIDLNames) {
adjective = ":";
}
for (int i = 0; i < interfaces.length; i++) {
if (!useIDLNames || (!interfaces[i].isType(TYPE_ANY) && !interfaces[i].isType(TYPE_CORBA_OBJECT))) {
if (i == 0) {
writer.p(prefix + adjective + " ");
} else {
writer.p(", ");
}
interfaces[i].printTypeName(writer,useQualifiedNames,useIDLNames,globalIDLNames);
}
}
}
// Print members
protected void printMembers ( IndentingWriter writer,
boolean useQualifiedNames,
boolean useIDLNames,
boolean globalIDLNames) throws IOException {
CompoundType.Member[] members = getMembers();
for (int i = 0; i < members.length; i++) {
if (!members[i].isInnerClassDeclaration()) {
Type it = members[i].getType();
String visibility = members[i].getVisibility();
String name;
if (useIDLNames) {
name = members[i].getIDLName();
} else {
name = members[i].getName();
}
String value = members[i].getValue();
writer.p(visibility);
if (visibility.length() > 0) {
writer.p(" ");
}
it.printTypeName(writer,useQualifiedNames,useIDLNames,globalIDLNames);
writer.p(" " + name);
if (value != null) {
writer.pln(" = " + value + ";");
} else {
writer.pln(";");
}
}
}
}
// Print methods
protected void printMethods ( IndentingWriter writer,
boolean useQualifiedNames,
boolean useIDLNames,
boolean globalIDLNames) throws IOException {
CompoundType.Method[] methods = getMethods();
for (int m = 0; m < methods.length; m++) {
CompoundType.Method theMethod = methods[m];
printMethod(theMethod,writer,useQualifiedNames,useIDLNames,globalIDLNames);
}
}
// Print a method...
protected void printMethod (CompoundType.Method it,
IndentingWriter writer,
boolean useQualifiedNames,
boolean useIDLNames,
boolean globalIDLNames) throws IOException {
// Write visibility...
String visibility = it.getVisibility();
writer.p(visibility);
if (visibility.length() > 0) {
writer.p(" ");
}
// Write return type...
it.getReturnType().printTypeName(writer,useQualifiedNames,useIDLNames,globalIDLNames);
// Write method name...
if (useIDLNames) {
writer.p(" " + it.getIDLName());
} else {
writer.p(" " + it.getName());
}
// Write arguments...
writer.p(" (");
Type[] args = it.getArguments();
String[] argNames = it.getArgumentNames();
for (int i = 0; i < args.length; i++) {
if (i > 0) {
writer.p(", ");
}
if (useIDLNames) {
writer.p("in ");
}
args[i].printTypeName(writer,useQualifiedNames,useIDLNames,globalIDLNames);
writer.p(" " + argNames[i]);
}
writer.p(")");
// Write exceptions...
ClassType[] exceptions;
if (isType(TYPE_IMPLEMENTATION)) {
exceptions = it.getImplExceptions();
} else {
exceptions = it.getExceptions();
}
for (int i = 0; i < exceptions.length; i++) {
if (i == 0) {
if (useIDLNames) {
writer.p(" raises (");
} else {
writer.p(" throws ");
}
} else {
writer.p(", ");
}
if (useIDLNames) {
if (useQualifiedNames) {
writer.p(exceptions[i].getQualifiedIDLExceptionName(globalIDLNames));
} else {
writer.p(exceptions[i].getIDLExceptionName());
}
writer.p(" [a.k.a. ");
exceptions[i].printTypeName(writer,useQualifiedNames,useIDLNames,globalIDLNames);
writer.p("]");
} else {
exceptions[i].printTypeName(writer,useQualifiedNames,useIDLNames,globalIDLNames);
}
}
if (useIDLNames && exceptions.length > 0) {
writer.p(")");
}
if (it.isInherited()) {
writer.p(" // Inherited from ");
writer.p(it.getDeclaredBy());
}
writer.pln(";");
}
/**
* Create a CompoundType instance for the given class. NOTE: This constructor
* is ONLY for SpecialClassType and SpecialInterfaceType.
*/
protected CompoundType(ContextStack stack, int typeCode, ClassDefinition classDef) {
super(stack,typeCode);
this.classDef = classDef;
classDecl = classDef.getClassDeclaration();
interfaces = new InterfaceType[0];
methods = new Method[0];
members = new Member[0];
// If we are an inner class/interface, reset the type codes...
if (classDef.isInnerClass()) {
setTypeCode(typeCode | TM_INNER);
}
// Set special flags...
setFlags();
}
private void setFlags() {
try {
// Set our special interface flags...
isCORBAObject = env.defCorbaObject.implementedBy(env,classDecl);
isIDLEntity = env.defIDLEntity.implementedBy(env,classDecl);
isValueBase = env.defValueBase.implementedBy(env,classDecl);
isAbstractBase = isInterface() && // Interface, not a class.
isIDLEntity && // Implements IDLEntity.
!isValueBase && // Does not implement ValueBase.
!isCORBAObject; // Does not implement org.omg.CORBA.Object;
isCORBAUserException = (classDecl.getName() == idCorbaUserException);
// Is this an exception?
if (env.defThrowable.implementedBy(env, classDecl)) {
// Yes...
isException = true;
// Is it a checked exception?
if (env.defRuntimeException.implementedBy(env,classDecl) ||
env.defError.implementedBy(env,classDecl)) {
isCheckedException = false;
} else {
isCheckedException = true;
}
// Is it java.rmi.RemoteException or a subclass?
if (env.defRemoteException.implementedBy(env,classDecl)) {
isRemoteExceptionOrSubclass = true;
} else {
isRemoteExceptionOrSubclass = false;
}
} else {
isException = false;
}
} catch (ClassNotFound e) {
classNotFound(stack,e);
}
}
/**
* Create a CompoundType instance for the given class. The resulting
* object is not yet completely initialized.
*/
protected CompoundType(ContextStack stack, ClassDefinition classDef,
int typeCode) {
super(stack,typeCode);
this.classDef = classDef;
classDecl = classDef.getClassDeclaration();
// If we are an inner class/interface, reset the type codes...
if (classDef.isInnerClass()) {
setTypeCode(typeCode | TM_INNER);
}
// Set special flags...
setFlags();
// Set names...
Identifier id = classDef.getName();
String idlName;
String[] idlModuleNames;
try {
// These can fail if we get case-sensitive name matches...
idlName = IDLNames.getClassOrInterfaceName(id,env);
idlModuleNames = IDLNames.getModuleNames(id,isBoxed(),env);
setNames(id,idlModuleNames,idlName);
// Is this an exception?
if (isException()) {
// Yes, so set our mangled exception names...
isException = true;
idlExceptionName = IDLNames.getExceptionName(getIDLName());
qualifiedIDLExceptionName =
IDLNames.getQualifiedName(getIDLModuleNames(),idlExceptionName);
}
// Set interfaces, methods and members...
interfaces = null; // set in initialize()
methods = null; // set in initialize()
members = null; // set in initialize()
} catch (Exception e) {
failedConstraint(7,false,stack,id.toString(),e.getMessage());
throw new CompilerError("");
}
}
/**
* Initialize this instance.
*/
protected boolean initialize ( Vector directInterfaces,
Vector directMethods,
Vector directMembers,
ContextStack stack,
boolean quiet) {
boolean result = true;
// Initialize our arrays...
if (directInterfaces != null && directInterfaces.size() > 0) {
interfaces = new InterfaceType[directInterfaces.size()];
directInterfaces.copyInto(interfaces);
} else {
interfaces = new InterfaceType[0];
}
if (directMethods != null && directMethods.size() > 0) {
methods = new Method[directMethods.size()];
directMethods.copyInto(methods);
// Now set the idl names for each...
try {
IDLNames.setMethodNames(this, methods,env);
} catch (Exception e) {
failedConstraint(13,quiet,stack,getQualifiedName(),e.getMessage());
result = false;
}
} else {
methods = new Method[0];
}
if (directMembers != null && directMembers.size() > 0) {
members = new Member[directMembers.size()];
directMembers.copyInto(members);
// If we have any un-initialized inner classes, now is the time
// to init them...
for (int i = 0; i < members.length; i++) {
if (members[i].isInnerClassDeclaration()) {
try {
members[i].init(stack,this);
} catch (CompilerError e) {
return false;
}
}
}
// Now set the idl names for each...
try {
IDLNames.setMemberNames(this, members,methods,env);
} catch (Exception e) {
int constraint = classDef.isInterface() ? 19 : 20;
failedConstraint(constraint,quiet,stack,getQualifiedName(),e.getMessage());
result = false;
}
} else {
members = new Member[0];
}
// Set our repositoryID...
if (result) {
result = setRepositoryID();
}
return result;
}
/*
* Return Type or null if error. classDef may be null.
*/
protected static Type makeType (sun.tools.java.Type theType,
ClassDefinition classDef,
ContextStack stack) {
if (stack.anyErrors()) return null;
// See if we can find this type in the cache. If so, return it...
String key = theType.toString();
Type result = getType(key,stack);
if (result != null) {
return result;
}
// Gotta try with context...
result = getType(key + stack.getContextCodeString(),stack);
if (result != null) {
return result;
}
// Gotta map it...
BatchEnvironment env = stack.getEnv();
int typeCode = theType.getTypeCode();
switch (typeCode) {
case TC_BOOLEAN:
case TC_BYTE:
case TC_CHAR:
case TC_SHORT:
case TC_INT:
case TC_LONG:
case TC_FLOAT:
case TC_DOUBLE:
{
// Primitive...
result = PrimitiveType.forPrimitive(theType,stack);
break;
}
case TC_ARRAY:
{
// Array.
result = ArrayType.forArray(theType,stack);
break;
}
case TC_CLASS:
{
try {
// First, make sure we have the class definition...
ClassDefinition theClass = classDef;
if (theClass == null) {
theClass = env.getClassDeclaration(theType).getClassDefinition(env);
}
// Is it an interface or a class?
if (theClass.isInterface()) {
// An interface. Is it a special case?
result = SpecialInterfaceType.forSpecial(theClass,stack);
if (result == null) {
// No, does it implement java.rmi.Remote?
if (env.defRemote.implementedBy(env,theClass.getClassDeclaration())) {
// Yep, so just see if we can create an instance of RemoteType
// from it...
boolean parentIsValue = stack.isParentAValue();
result = RemoteType.forRemote(theClass,stack,parentIsValue);
// If we did not succeed AND we are in a value context, then
// go ahead and make an NC type out of it...
if (result == null && parentIsValue) {
result = NCInterfaceType.forNCInterface(theClass,stack);
}
} else {
// Nope, is it an AbstractType?
result = AbstractType.forAbstract(theClass,stack,true);
if (result == null) {
// No, so treat it as a non-conforming interface type...
result = NCInterfaceType.forNCInterface(theClass,stack);
}
}
}
} else {
// A class. Is it a special case?
result = SpecialClassType.forSpecial(theClass,stack);
if (result == null) {
ClassDeclaration classDecl = theClass.getClassDeclaration();
// Nope, does it implement java.rmi.Remote?
if (env.defRemote.implementedBy(env,classDecl)) {
// Yep, so just see if we can create an instance of
// ImplementationType from it...
boolean parentIsValue = stack.isParentAValue();
result = ImplementationType.forImplementation(theClass,stack,parentIsValue);
// If we did not succeed AND inValue is true, then
// go ahead and make an NC type out of it...
if (result == null && parentIsValue) {
result = NCClassType.forNCClass(theClass,stack);
}
} else {
// No, does it implement Serializable?
if (env.defSerializable.implementedBy(env,classDecl)) {
// Yep, so just see if we can create an instance of ValueType
// from it...
result = ValueType.forValue(theClass,stack,true);
}
if (result == null) {
// Treat it as a non-conforming class type...
result = NCClassType.forNCClass(theClass,stack);
}
}
}
}
} catch (ClassNotFound e) {
classNotFound(stack,e);
}
break;
}
default: throw new CompilerError("Unknown typecode (" + typeCode + ") for " + theType.getTypeSignature());
}
return result;
}
/*
* Check if exception is RemoteException or one of its parents.
*/
public static boolean isRemoteException (ClassType ex,
BatchEnvironment env) {
sun.tools.java.Type exceptionType = ex.getClassDeclaration().getType();
if (exceptionType.equals(env.typeRemoteException) ||
exceptionType.equals(env.typeIOException) ||
exceptionType.equals(env.typeException) ||
exceptionType.equals(env.typeThrowable)) {
return true;
}
return false;
}
/*
* Check if method is conforming.
*/
protected boolean isConformingRemoteMethod (Method method, boolean quiet)
throws ClassNotFound {
// Do we have one exception that is RemoteException or
// a superclass of RemoteException?
boolean haveRemote = false;
ClassType[] exceptions = method.getExceptions();
for (int i = 0; i < exceptions.length; i++) {
// Is it a conforming exception?
if (isRemoteException(exceptions[i],env)) {
// Got it.
haveRemote = true;
break;
}
}
// Do we have our exception?
if (!haveRemote) {
// No, so report failure...
failedConstraint(5,quiet,stack,method.getEnclosing(), method.toString());
}
// Are any of the arguments exceptions which implement IDLEntity?
// If so, report failure...
boolean noIDLEntity = !isIDLEntityException(method.getReturnType(),method,quiet);
if (noIDLEntity) {
Type[] args = method.getArguments();
for (int i = 0; i < args.length; i++) {
if (isIDLEntityException(args[i],method,quiet)) {
noIDLEntity = false;
break;
}
}
}
return (haveRemote && noIDLEntity);
}
protected boolean isIDLEntityException(Type type, CompoundType.Method method,boolean quiet)
throws ClassNotFound {
if (type.isArray()) {
type = type.getElementType();
}
if (type.isCompound()){
if (((CompoundType)type).isIDLEntityException()) {
failedConstraint(18,quiet,stack,method.getEnclosing(), method.toString());
return true;
}
}
return false;
}
/**
* Convert all invalid types to valid ones.
*/
protected void swapInvalidTypes () {
// Walk all interfaces and check them...
for (int i = 0; i < interfaces.length; i++) {
if (interfaces[i].getStatus() != STATUS_VALID) {
interfaces[i] = (InterfaceType)getValidType(interfaces[i]);
}
}
// Update methods...
for (int i = 0; i < methods.length; i++) {
methods[i].swapInvalidTypes();
}
// Update members...
for (int i = 0; i < members.length; i++) {
members[i].swapInvalidTypes();
}
}
/*
* Add matching types to list. Return true if this type has not
* been previously checked, false otherwise.
*/
protected boolean addTypes (int typeCodeFilter,
HashSet checked,
Vector matching) {
// Check self.
boolean result = super.addTypes(typeCodeFilter,checked,matching);
// Have we been checked before?
if (result) {
// Nope, so walk parent(s) and check them...
ClassType parent = getSuperclass();
if (parent != null) {
parent.addTypes(typeCodeFilter,checked,matching);
}
// Walk all interfaces and check them...
//if (interfaces == null) System.out.println("NULL for " +getQualifiedName() + " interfaces");
for (int i = 0; i < interfaces.length; i++) {
// Now recurse and add it and any referenced types...
//if (interfaces[i] == null) System.out.println("NULL for " +getQualifiedName() + " interfaces[" + i + "]");
interfaces[i].addTypes(typeCodeFilter,checked,matching);
}
// Walk all methods and check arguments...
//if (methods == null) System.out.println("NULL for " +getQualifiedName() + " methods");
for (int i = 0; i < methods.length; i++) {
// Add return type...
//if (methods[i] == null) System.out.println("NULL for " +getQualifiedName() + " methods[" + i + "]");
//if (methods[i].getReturnType() == null) System.out.println("NULL for " +getQualifiedName() + methods[i]);
methods[i].getReturnType().addTypes(typeCodeFilter,checked,matching);
// Add args...
Type[] args = methods[i].getArguments();
//if (args == null) System.out.println("NULL for " + getQualifiedName() + " args");
for (int j = 0; j < args.length; j++) {
Type arg = args[j];
//if (arg == null) System.out.println("NULL for " + getQualifiedName() + " arg[" +j+"]");
// Add argument...
arg.addTypes(typeCodeFilter,checked,matching);
}
// Add exceptions...
ClassType[] exceptions = methods[i].getExceptions();
//if (exceptions == null) System.out.println("NULL for " + getQualifiedName() + " exceptions");
for (int j = 0; j < exceptions.length; j++) {
ClassType ex = exceptions[j];
// Add argument...
ex.addTypes(typeCodeFilter,checked,matching);
}
}
// Walk all members and add em...
//if (members == null) System.out.println("NULL for " +getQualifiedName() + " members");
for (int i = 0; i < members.length; i++) {
//if (members[i] == null) System.out.println("NULL for " +getQualifiedName() + " members[" + i + "]");
Type cType = members[i].getType();
//if (cType == null) System.out.println("NULL for " + getQualifiedName() + " cType");
// Add it...
cType.addTypes(typeCodeFilter,checked,matching);
}
}
return result;
}
/*
* Return true if theType is a conforming constant type.
*/
private boolean isConformingConstantType (MemberDefinition member) {
return isConformingConstantType(member.getType(),member);
}
/*
* Return true if theType is a conforming constant type.
*/
private boolean isConformingConstantType (sun.tools.java.Type theType,MemberDefinition member) {
// Constraint 3: Constants must be either primitives or String.
boolean result = true;
int typeCode = theType.getTypeCode();
switch (typeCode) {
case TC_BOOLEAN:
case TC_BYTE:
case TC_CHAR:
case TC_SHORT:
case TC_INT:
case TC_LONG:
case TC_FLOAT:
case TC_DOUBLE: // Primitive, so OK...
{
break;
}
case TC_CLASS: // Must be java.lang.String
{
if (theType.getClassName() != idJavaLangString) {
failedConstraint(3,false,stack,member.getClassDefinition(),member.getName());
result = false;
}
break;
}
case TC_ARRAY: // Array constants are not allowed.
{
failedConstraint(3,false,stack,member.getClassDefinition(),member.getName());
result = false;
break;
}
default:
throw new Error("unexpected type code: " + typeCode);
}
return result;
}
/*
* Update any method from 'currentMethods' which is defined in a
* parent class so that it's 'declaredBy' field specifies the
* parent.
* @param current The class or interface to gather methods from.
* @param currentMethods The list into which to put the methods.
* for contraint 6.
* @param quiet true if silent errors.
* @param stack the context stack.
* @return currentMethods or null if failed a constraint check.
*/
protected Vector updateParentClassMethods(ClassDefinition current,
Vector currentMethods,
boolean quiet,
ContextStack stack)
throws ClassNotFound {
ClassDeclaration parentDecl = current.getSuperClass(env);
while (parentDecl != null) {
ClassDefinition parentDef = parentDecl.getClassDefinition(env);
Identifier currentID = parentDecl.getName();
if ( currentID == idJavaLangObject ) break;
// Walk all members of this class and update any that
// already exist in currentMethods...
for (MemberDefinition member = parentDef.getFirstMember();
member != null;
member = member.getNextMember()) {
if (member.isMethod() &&
!member.isInitializer() &&
!member.isConstructor() &&
!member.isPrivate()) {
// It's a method. Is it valid?
Method method;
try {
method = new Method((CompoundType)this,member,quiet,stack);
} catch (Exception e) {
// Don't report anything here, it's already been reported...
return null;
}
// Have we already seen it?
int index = currentMethods.indexOf(method);
if (index >= 0) {
// Yes, so update it...
Method currentMethod = (Method)currentMethods.elementAt(index);
currentMethod.setDeclaredBy(currentID);
}
else currentMethods.addElement(method);
}
}
// Update parent and keep walking up the chain...
parentDecl = parentDef.getSuperClass(env);
}
return currentMethods;
}
/*
* Add all of the public and protected methods defined in
* current (other than initializers) to allMethods. If a sub-interface
* re-declares an inherited method, it will not be added.
* @param current The class or interface to gather methods from.
* @param directMethods The list into which to put the methods.
* @param noMultiInheritedMethods A flag to enable/disable checking
* for contraint 6.
* @param quiet true if silent errors.
* @param stack the context stack.
* @return directMethods or null if failed a constraint check.
*/
protected Vector addAllMethods (ClassDefinition current, Vector directMethods,
boolean noMultiInheritedMethods,
boolean quiet,
ContextStack stack)
throws ClassNotFound {
// Constraint 6: Multiple inherited interfaces may not
// declare the same method.
ClassDeclaration[] interfaces = current.getInterfaces();
// We want to add members starting at the _least_ derived
// interfaces. To do so, recurse until we have no more
// interfaces...
for (int i = 0; i < interfaces.length; i++) {
Vector result = addAllMethods(interfaces[i].getClassDefinition(env),
directMethods,
noMultiInheritedMethods,quiet,stack);
if (result == null) {
return null;
}
}
// Walk all members of this interface, adding any unique methods
// other than initializers and private methods...
for (MemberDefinition member = current.getFirstMember();
member != null;
member = member.getNextMember())
{
if (member.isMethod() &&
!member.isInitializer() &&
!member.isPrivate()) {
// It's a method. Is it valid?
Method method;
try {
method = new Method((CompoundType)this,member,quiet,stack);
} catch (Exception e) {
// Don't report anything here, it's already been reported...
return null;
}
// Have we already seen it?
if (!directMethods.contains(method)) {
// Nope, so add it...
directMethods.addElement(method);
} else {
// Yes. This is an error unless we are looking at the
// target interface (or this is a ValueType). Are we?
if (noMultiInheritedMethods && current != classDef &&
!stack.isParentAValue() && !stack.getContext().isValue()) {
// Nope. Say so and signal error by returning null..
Method existingMethod = (Method) directMethods.elementAt(directMethods.indexOf(method));
ClassDefinition existingMemberClassDef = existingMethod.getMemberDefinition().getClassDefinition();
// There are more legal cases to consider here.
// If the two methods belong to interfaces that inherit from each other
// then it is just a redefinition which is legal.
if ( current != existingMemberClassDef &&
! inheritsFrom(current, existingMemberClassDef) &&
! inheritsFrom(existingMemberClassDef, current))
{
//Identifier int1 = existingMethod.getEnclosing().getIdentifier();
//Identifier int2 = current.getName();
//String message = int1.toString() + " and " + int2.toString();
String message = existingMemberClassDef.getName() + " and " + current.getName();
failedConstraint(6,quiet,stack,classDef,message,method);
return null;
}
}
// Bug fix 5014329
// find a matching method.
int index = directMethods.indexOf(method);
Method other = (Method) directMethods.get(index);
// merge the two methods, such that the new method
// will contain only those exception that can be thrown
// by both these methods, not just one of them.
Method newMethod = method.mergeWith(other);
// replace the old method with the new.
directMethods.set(index, newMethod);
}
}
}
return directMethods;
}
// This should really be a method on ClassDefinition, but it takes too long to change the shared source.
// Works for both, classes and interfaces.
protected boolean inheritsFrom(ClassDefinition def, ClassDefinition otherDef) {
if (def == otherDef)
return true;
ClassDefinition superDef;
if (def.getSuperClass() != null) {
superDef = def.getSuperClass().getClassDefinition();
if (inheritsFrom(superDef, otherDef))
return true;
}
ClassDeclaration[] interfaces = def.getInterfaces();
for (int i=0; i<interfaces.length; i++) {
superDef = interfaces[i].getClassDefinition();
if (inheritsFrom(superDef, otherDef))
return true;
}
return false;
}
/*
* Add all of the interfaces implemented directly by current
* to the list. Returns null if any are non-conforming.
*/
protected Vector addRemoteInterfaces (Vector list,
boolean allowNonConforming,
ContextStack stack) throws ClassNotFound {
// Add all the interfaces of current...
ClassDefinition theInterface = getClassDefinition();
ClassDeclaration[] interfaces = theInterface.getInterfaces();
stack.setNewContextCode(ContextStack.IMPLEMENTS);
for (int i = 0; i < interfaces.length; i++) {
ClassDefinition def = interfaces[i].getClassDefinition(env);
// Is it a SpecialInterfaceType...
InterfaceType it = SpecialInterfaceType.forSpecial(def,stack);;
if (it == null) {
// No, is it Remote?
if (env.defRemote.implementedBy(env, interfaces[i])) {
// Yes, so it must be a RemoteType.
it = RemoteType.forRemote(def,stack,false);
} else {
// Then try Abstract...
it = AbstractType.forAbstract(def,stack,true);
if (it == null && allowNonConforming) {
// Must be non-conforming...
it = NCInterfaceType.forNCInterface(def,stack);
}
}
}
if (it != null) {
list.addElement(it);
} else {
return null;
}
}
return list;
}
/*
* Add all of the interfaces implemented directly by current
* to the list.
*/
protected Vector addNonRemoteInterfaces (Vector list,
ContextStack stack) throws ClassNotFound {
// Add all the interfaces of current...
ClassDefinition theInterface = getClassDefinition();
ClassDeclaration[] interfaces = theInterface.getInterfaces();
stack.setNewContextCode(ContextStack.IMPLEMENTS);
for (int i = 0; i < interfaces.length; i++) {
ClassDefinition def = interfaces[i].getClassDefinition(env);
// First try SpecialInterfaceType...
InterfaceType it = SpecialInterfaceType.forSpecial(def,stack);
if (it == null) {
// Then try AbstractType...
it = AbstractType.forAbstract(def,stack,true);
if (it == null) {
// Then try NCInterfaceType...
it = NCInterfaceType.forNCInterface(def,stack);
}
}
if (it != null) {
list.addElement(it);
} else {
return null;
}
}
return list;
}
/*
* Walk self, adding constants and data members.
* @return true if all conform, false otherwise.
*/
protected boolean addAllMembers (Vector allMembers,
boolean onlyConformingConstants, // AND inner classes.
boolean quiet,
ContextStack stack) {
boolean result = true;
// Walk all members of this interface...
for (MemberDefinition member = getClassDefinition().getFirstMember();
member != null && result;
member = member.getNextMember())
{
if (!member.isMethod()) {
try {
String value = null;
// Prod it to setValue if it is a constant...
member.getValue(env);
// Get the value, if any...
Node node = member.getValue();
if (node != null) {
// We don't want to change the code in CharExpression,
// which is shared among tools, to return the right string
// in case the type is char, so we treat it special here.
if (member.getType().getTypeCode() == TC_CHAR) {
Integer intValue = (Integer)((IntegerExpression)node).getValue();
value = "L'" + String.valueOf((char)intValue.intValue()) + "'";
} else {
value = node.toString();
}
}
// Are we supposed to allow only conforming constants?
if (onlyConformingConstants && member.getInnerClass() == null) {
// Yep, so check it...
if (value == null || !isConformingConstantType(member)) {
failedConstraint(3,quiet,stack,member.getClassDefinition(),member.getName());
result = false;
break;
}
}
// Make member and add to list...
try {
Member newMember = new Member(member,value,stack,this);
allMembers.addElement(newMember);
} catch (CompilerError e) {
result = false;
}
} catch (ClassNotFound e) {
classNotFound(stack,e);
result = false;
}
}
}
return result;
}
/*
* Walk self, adding constants.
* @return true if all conform, false otherwise.
*/
protected boolean addConformingConstants (Vector allMembers,
boolean quiet,
ContextStack stack) {
boolean result = true;
// Walk all members of this interface...
for (MemberDefinition member = getClassDefinition().getFirstMember();
member != null && result;
member = member.getNextMember())
{
if (!member.isMethod()) {
try {
String value = null;
// Prod it to setValue if it is a constant...
member.getValue(env);
// Get the value, if any...
Node node = member.getValue();
if (node != null) {
value = node.toString();
}
// Is it a constant?
if (value != null) {
// Yes, is it conforming?
if (!isConformingConstantType(member)) {
failedConstraint(3,quiet,stack,member.getClassDefinition(),member.getName());
result = false;
break;
}
// Yes, so make a member and add to list...
try {
Member newMember = new Member(member,value,stack,this);
allMembers.addElement(newMember);
} catch (CompilerError e) {
result = false;
}
}
} catch (ClassNotFound e) {
classNotFound(stack,e);
result = false;
}
}
}
return result;
}
protected ValueType[] getMethodExceptions (MemberDefinition member,
boolean quiet,
ContextStack stack) throws Exception {
boolean result = true;
stack.setNewContextCode(ContextStack.METHOD_EXCEPTION);
ClassDeclaration[] except = member.getExceptions(env);
ValueType[] exceptions = new ValueType[except.length];
try {
for (int i = 0; i < except.length; i++) {
ClassDefinition theClass = except[i].getClassDefinition(env);
try {
ValueType type = ValueType.forValue(theClass,stack,false);
if (type != null) {
exceptions[i] = type;
} else {
result = false;
}
} catch (ClassCastException e1) {
failedConstraint(22,quiet,stack,getQualifiedName());
throw new CompilerError("Method: exception " + theClass.getName() + " not a class type!");
} catch (NullPointerException e2) {
failedConstraint(23,quiet,stack,getQualifiedName());
throw new CompilerError("Method: caught null pointer exception");
}
}
} catch (ClassNotFound e) {
classNotFound(quiet,stack,e);
result = false;
}
if (!result) {
throw new Exception();
}
// Remove any duplicates (javac seems to allow them, but rmic will
// generate bad ties)...
int dupCount = 0;
for (int i = 0; i < exceptions.length; i++) {
for (int j = 0; j < exceptions.length; j++) {
if (i != j && exceptions[i] != null && exceptions[i] == exceptions[j]) {
exceptions[j] = null;
dupCount++;
}
}
}
if (dupCount > 0) {
int offset = 0;
ValueType[] temp = new ValueType[exceptions.length - dupCount];
for (int i = 0; i < exceptions.length; i++) {
if (exceptions[i] != null) {
temp[offset++] = exceptions[i];
}
}
exceptions = temp;
}
return exceptions;
}
protected static String getVisibilityString (MemberDefinition member) {
String vis = "";
String prefix = "";
if (member.isPublic()) {
vis += "public";
prefix = " ";
} else if (member.isProtected()) {
vis += "protected";
prefix = " ";
} else if (member.isPrivate()) {
vis += "private";
prefix = " ";
}
if (member.isStatic()) {
vis += prefix;
vis += "static";
prefix = " ";
}
if (member.isFinal()) {
vis += prefix;
vis += "final";
prefix = " ";
}
return vis;
}
protected boolean assertNotImpl(Type type,
boolean quiet,
ContextStack stack,
CompoundType enclosing,
boolean dataMember) {
if (type.isType(TYPE_IMPLEMENTATION)) {
int constraint = dataMember ? 28 : 21;
failedConstraint(constraint,quiet,stack,type,enclosing.getName());
return false;
}
return true;
}
//_____________________________________________________________________
// Inner Class "Method"
//_____________________________________________________________________
/**
* A CompoundType.Method object encapsulates IIOP-specific information
* about a particular method in the interface represented by the outer
* instance.
*/
public class Method implements ContextElement, Cloneable {
/**
* Is this method inherited?
*/
public boolean isInherited () {
return declaredBy != enclosing.getIdentifier();
}
/**
* Is this method an attribute?
* Return true if getAttributeKind != ATTRIBUTE_NONE.
*/
public boolean isAttribute () {
return attributeKind != ATTRIBUTE_NONE;
}
/**
* Is this method a read-write attribute?
*/
public boolean isReadWriteAttribute () {
return attributeKind == ATTRIBUTE_IS_RW ||
attributeKind == ATTRIBUTE_GET_RW;
}
/**
* Return the attribute kind.
*/
public int getAttributeKind() {
return attributeKind;
}
/**
* Return the attribute name. Will be null if
* attribute kind == ATTRIBUTE_NONE.
*/
public String getAttributeName() {
return attributeName;
}
/**
* For kinds ATTRIBUTE_GET_RW or ATTRIBUTE_IS_RW, return
* the index of the matching ATTRIBUTE_SET method, and
* vice-versa. For all other cases, return -1.
*/
public int getAttributePairIndex() {
return attributePairIndex;
}
/**
* Return context element name.
*/
public String getElementName() {
return memberDef.toString();
}
/**
* Equality check based on method signature.
*/
public boolean equals(Object obj) {
Method other = (Method) obj;
if (getName().equals(other.getName()) &&
arguments.length == other.arguments.length) {
for (int i = 0; i < arguments.length; i++) {
if (! arguments[i].equals(other.arguments[i])) {
return false;
}
}
return true;
}
return false;
}
public int hashCode() {
return getName().hashCode() ^ Arrays.hashCode(arguments);
}
/**
* Return a new Method object that is a legal combination of
* this method object and another one.
*
* This requires determining the exceptions declared by the
* combined method, which must be only those exceptions
* that may thrown by both of the old methods.
*/
public Method mergeWith(Method other) {
if (!equals(other)) {
env.error(0, "attempt to merge method failed:", getName(),
enclosing.getClassDefinition().getName());
}
Vector legalExceptions = new Vector();
try {
collectCompatibleExceptions(
other.exceptions, exceptions, legalExceptions);
collectCompatibleExceptions(
exceptions, other.exceptions, legalExceptions);
} catch (ClassNotFound e) {
env.error(0, "class.not.found", e.name,
enclosing.getClassDefinition().getName());
return null;
}
Method merged = (Method) clone();
merged.exceptions = new ValueType[legalExceptions.size()];
legalExceptions.copyInto(merged.exceptions);
merged.implExceptions = merged.exceptions;
return merged;
}
/**
* Add to the supplied list all exceptions in the "from" array
* that are subclasses of an exception in the "with" array.
*/
private void collectCompatibleExceptions(
ValueType[] from, ValueType[] with, Vector list)
throws ClassNotFound {
for (int i = 0; i < from.length; i++) {
ClassDefinition exceptionDef = from[i].getClassDefinition();
if (!list.contains(from[i])) {
for (int j = 0; j < with.length; j++) {
if (exceptionDef.subClassOf(
enclosing.getEnv(),
with[j].getClassDeclaration())) {
list.addElement(from[i]);
break;
}
}
}
}
}
/**
* Return the compound type which contains this method.
*/
public CompoundType getEnclosing() {
return enclosing;
}
/**
* Return the identifier for the class or interface which
* declares this method.
*/
public Identifier getDeclaredBy() {
return declaredBy;
}
/**
* Return the visibility (e.g. "public final") of this member.
*/
public String getVisibility() {
return vis;
}
/**
* Methods to check various attributes.
*/
public boolean isPublic() {
return memberDef.isPublic();
}
public boolean isProtected() {
return memberDef.isPrivate();
}
public boolean isPrivate() {
return memberDef.isPrivate();
}
public boolean isStatic() {
return memberDef.isStatic();
}
/**
* Return the name of this method.
*/
public String getName() {
return name;
}
/**
* IDL_Naming
* Return the IDL name of this method.
*/
public String getIDLName() {
return idlName;
}
/**
* Return the type of this method.
*/
public sun.tools.java.Type getType() {
return memberDef.getType();
}
/**
* Return true if this is a constructor.
*/
public boolean isConstructor () {
return memberDef.isConstructor();
}
/**
* Return true if this is NOT a constructor && is not
* an attribute.
*/
public boolean isNormalMethod () {
return (!memberDef.isConstructor()) && attributeKind == ATTRIBUTE_NONE;
}
/**
* Get the return type of this method. May be null.
*/
public Type getReturnType() {
return returnType;
}
/**
* Return the argument types of this method.
*/
public Type[] getArguments() {
return (Type[]) arguments.clone();
}
/**
* Return the names of the argument types of this method.
*/
public String[] getArgumentNames() {
return argumentNames;
}
/**
* Return the MemberDefinition from which this method was created.
*/
public MemberDefinition getMemberDefinition() {
return memberDef;
}
/**
* Return an array of the exception classes declared to be
* thrown by this remote method.
*
* For methods with the same name and type signature inherited
* from multiple remote interfaces, the array will contain
* the set of exceptions declared in all of the interfaces'
* methods that can be legally thrown in each of them.
*/
public ValueType[] getExceptions() {
return (ValueType[]) exceptions.clone();
}
/**
* Same as getExceptions(), except when method is in an
* ImplementationType and the exceptions list is narrower.
*/
public ValueType[] getImplExceptions() {
return (ValueType[]) implExceptions.clone();
}
/**
* Return an array containing only those exceptions which
* need to be caught. Removes java.rmi.RemoteException,
* java.lang.RuntimeException, java.lang.Error, and their
* subclasses, then removes any exceptions which are more
* derived than another in the list. Returns null if no
* exceptions need to be caught.
*/
public ValueType[] getUniqueCatchList(ValueType[] list) {
ValueType[] result = list;
int newSize = list.length;
try {
// First, remove RemoteException, RuntimeException, Error, and their subclasses...
for (int i = 0; i < list.length; i++) {
ClassDeclaration decl = list[i].getClassDeclaration();
if (env.defRemoteException.superClassOf(env, decl) ||
env.defRuntimeException.superClassOf(env, decl) ||
env.defError.superClassOf(env, decl)) {
list[i] = null;
newSize--;
}
}
// Now remove derived types...
for (int i = 0; i < list.length; i++) {
if (list[i] != null) {
ClassDefinition current = list[i].getClassDefinition();
for (int j = 0; j < list.length; j++) {
if (j != i && list[i] != null && list[j] != null &&
current.superClassOf(env, list[j].getClassDeclaration())) {
list[j] = null;
newSize--;
}
}
}
}
} catch (ClassNotFound e) {
classNotFound(stack,e); // Report error but do not stop.
}
// Create new list if we removed anything...
if (newSize < list.length) {
ValueType[] temp = new ValueType[newSize];
int offset = 0;
for (int i = 0; i < list.length; i++) {
if (list[i] != null) {
temp[offset++] = list[i];
}
}
list = temp;
}
if (list.length == 0) {
return null;
} else {
return list;
}
}
/**
* Return an array containing only those exceptions which need to be
* handled explicitly by the stub. Removes java.lang.RuntimeException,
* java.lang.Error, and their subclasses, since these are all passed
* back as CORBA system exceptions. Also removes subclasses of
* java.rmi.RemoteException but not java.rmi.RemoteException itself,
* since this may need to be thrown by the stub.
*/
public ValueType[] getFilteredStubExceptions(ValueType[] list) {
ValueType[] result = list;
int newSize = list.length;
try {
for (int i = 0; i < list.length; i++) {
ClassDeclaration decl = list[i].getClassDeclaration();
if ((env.defRemoteException.superClassOf(env, decl) &&
!env.defRemoteException.getClassDeclaration().equals(decl)) ||
env.defRuntimeException.superClassOf(env, decl) ||
env.defError.superClassOf(env, decl)) {
list[i] = null;
newSize--;
}
}
} catch (ClassNotFound e) {
classNotFound(stack,e); // Report error but do not stop.
}
// Create new list if we removed anything...
if (newSize < list.length) {
ValueType[] temp = new ValueType[newSize];
int offset = 0;
for (int i = 0; i < list.length; i++) {
if (list[i] != null) {
temp[offset++] = list[i];
}
}
list = temp;
}
return list;
}
/**
* Return the string representation of this method.
*/
public String toString() {
if (stringRep == null) {
StringBuffer result = new StringBuffer(returnType.toString());
// Add name...
result.append(" ");
result.append(getName());
result.append(" (");
// Add arguments...
for (int i = 0; i < arguments.length; i++) {
if (i > 0) {
result.append(", ");
}
result.append(arguments[i]);
result.append(" ");
result.append(argumentNames[i]);
}
result.append(")");
// Add exceptions...
for (int i = 0; i < exceptions.length; i++) {
if (i == 0) {
result.append(" throws ");
} else {
result.append(", ");
}
result.append(exceptions[i]);
}
result.append(";");
stringRep = result.toString();
}
return stringRep;
}
/**
* Set attribute kind. May only be called during initialization.
*/
public void setAttributeKind(int kind) {
attributeKind = kind;
}
/**
* Set pair index. May only be called during initialization.
*/
public void setAttributePairIndex(int index) {
attributePairIndex = index;
}
/**
* Set attribute name. May only be called during initialization.
*/
public void setAttributeName(String name) {
attributeName = name;
}
/**
* Set the idl name. May only be called during initialization.
*/
public void setIDLName (String idlName) {
this.idlName=idlName;
}
/**
* Set the implExceptions array. May only be called during initialization.
*/
public void setImplExceptions (ValueType[] exceptions) {
implExceptions = exceptions;
}
/**
* Set the declaredBy Identifier. May only be called during initialization.
*/
public void setDeclaredBy (Identifier by) {
declaredBy = by;
}
/**
* Convert all invalid types to valid ones.
*/
protected void swapInvalidTypes () {
// Check return type...
if (returnType.getStatus() != STATUS_VALID) {
returnType = getValidType(returnType);
}
// Check args...
for (int i = 0; i < arguments.length; i++) {
if (arguments[i].getStatus() != STATUS_VALID) {
arguments[i] = getValidType(arguments[i]);
}
}
// Check exceptions...
for (int i = 0; i < exceptions.length; i++) {
if (exceptions[i].getStatus() != STATUS_VALID) {
exceptions[i] = (ValueType)getValidType(exceptions[i]);
}
}
// Check implExceptions...
for (int i = 0; i < implExceptions.length; i++) {
if (implExceptions[i].getStatus() != STATUS_VALID) {
implExceptions[i] = (ValueType)getValidType(implExceptions[i]);
}
}
}
/**
* Release all resources.
*/
public void destroy () {
if (memberDef != null) {
memberDef = null;
enclosing = null;
if (exceptions != null) {
for (int i = 0; i < exceptions.length; i++) {
if (exceptions[i] != null) exceptions[i].destroy();
exceptions[i] = null;
}
exceptions = null;
}
if (implExceptions != null) {
for (int i = 0; i < implExceptions.length; i++) {
if (implExceptions[i] != null) implExceptions[i].destroy();
implExceptions[i] = null;
}
implExceptions = null;
}
if (returnType != null) returnType.destroy();
returnType = null;
if (arguments != null) {
for (int i = 0; i < arguments.length; i++) {
if (arguments[i] != null) arguments[i].destroy();
arguments[i] = null;
}
arguments = null;
}
if (argumentNames != null) {
for (int i = 0; i < argumentNames.length; i++) {
argumentNames[i] = null;
}
argumentNames = null;
}
vis = null;
name = null;
idlName = null;
stringRep = null;
attributeName = null;
declaredBy = null;
}
}
private MemberDefinition memberDef;
private CompoundType enclosing;
private ValueType[] exceptions;
private ValueType[] implExceptions;
private Type returnType;
private Type[] arguments;
private String[] argumentNames;
private String vis;
private String name;
private String idlName;
private String stringRep = null;
private int attributeKind = ATTRIBUTE_NONE;
private String attributeName = null;
private int attributePairIndex = -1;
private Identifier declaredBy = null;
/**
* Make up an argument name for the given type.
*/
private String makeArgName (int argNum, Type type) {
return "arg" + argNum;
}
/**
* Create a new Method object corresponding to the given
* method definition.
*/
public Method (CompoundType enclosing,
MemberDefinition memberDef,
boolean quiet,
ContextStack stack) throws Exception {
this.enclosing = enclosing;
this.memberDef = memberDef;
vis = getVisibilityString(memberDef);
idlName = null; // See setIDLName()
boolean valid = true;
declaredBy = memberDef.getClassDeclaration().getName();
// Set name...
name = memberDef.getName().toString();
// Update the context...
stack.setNewContextCode(ContextStack.METHOD);
stack.push(this);
// Set return type...
stack.setNewContextCode(ContextStack.METHOD_RETURN);
sun.tools.java.Type methodType = memberDef.getType();
sun.tools.java.Type rtnType = methodType.getReturnType();
if (rtnType == sun.tools.java.Type.tVoid) {
returnType = PrimitiveType.forPrimitive(rtnType,stack);
} else {
returnType = makeType(rtnType,null,stack);
if (returnType == null ||
!assertNotImpl(returnType,quiet,stack,enclosing,false)) {
valid = false;
failedConstraint(24,quiet,stack,enclosing.getName());
}
}
// Set arguments and argument names...
stack.setNewContextCode(ContextStack.METHOD_ARGUMENT);
sun.tools.java.Type[] args = memberDef.getType().getArgumentTypes();
arguments = new Type[args.length];
argumentNames = new String[args.length];
Vector origArgNames = memberDef.getArguments();
for (int i = 0; i < args.length; i++) {
Type type = null;
try {
type = makeType(args[i],null,stack);
} catch (Exception e) {
}
if (type != null) {
if (!assertNotImpl(type,quiet,stack,enclosing,false)) {
valid = false;
} else {
arguments[i] = type;
if (origArgNames != null) {
LocalMember local = (LocalMember)origArgNames.elementAt(i+1);
argumentNames[i] = local.getName().toString();
} else {
argumentNames[i] = makeArgName(i,type);
}
}
} else {
valid = false;
failedConstraint(25,false,stack,enclosing.getQualifiedName(),name);
}
}
if (!valid) {
stack.pop(false);
throw new Exception();
}
// Set exceptions...
try {
exceptions = enclosing.getMethodExceptions(memberDef,quiet,stack);
implExceptions = exceptions;
stack.pop(true);
} catch (Exception e) {
stack.pop(false);
throw new Exception();
}
}
/**
* Cloning is supported by returning a shallow copy of this object.
*/
protected Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new Error("clone failed");
}
}
}
//_____________________________________________________________________
// Inner Class "Member"
//_____________________________________________________________________
/**
* An CompoundType.Member object wraps a Type and a value representing
* a data member, including constants.
*/
public class Member implements ContextElement, Cloneable {
/**
* Return context element name.
*/
public String getElementName() {
return "\"" + getName() + "\"";
}
/**
* Return the type of this member.
*/
public Type getType() {
return type;
}
/**
* Return the name of this member.
*/
public String getName() {
return name;
}
/**
* IDL_Naming
* Return the IDL name of this member.
*/
public String getIDLName() {
return idlName;
}
/**
* Return the visibility (e.g. "public final") of this member.
*/
public String getVisibility() {
return vis;
}
/**
* Methods to check various attributes.
*/
public boolean isPublic() {
return member.isPublic();
}
public boolean isPrivate() {
return member.isPrivate();
}
public boolean isStatic() {
return member.isStatic();
}
public boolean isFinal() {
return member.isFinal();
}
public boolean isTransient() {
if (forceTransient) return true;
return member.isTransient();
}
/**
* Return the value of this member. May be null.
*/
public String getValue() {
return value;
}
/**
* Return true if this member represents an inner class declaration,
* false otherwise.
*/
public boolean isInnerClassDeclaration() {
return innerClassDecl;
}
/**
* Return true if this member represents a constant.
*/
public boolean isConstant () {
return constant;
}
/**
* Return the string representation of this constant.
*/
public String toString() {
String result = type.toString();
if (value != null) {
result += (" = " + value);
}
return result;
}
/**
* Convert all invalid types to valid ones.
*/
protected void swapInvalidTypes () {
if (type.getStatus() != STATUS_VALID) {
type = getValidType(type);
}
}
protected void setTransient() {
if (! isTransient()) {
forceTransient = true;
if (vis.length() > 0) {
vis = vis + " transient";
} else {
vis = "transient";
}
}
}
protected MemberDefinition getMemberDefinition() {
return member;
}
/**
* Release all resources.
*/
public void destroy () {
if (type != null) {
type.destroy();
type = null;
vis = null;
value = null;
name = null;
idlName = null;
member = null;
}
}
private Type type;
private String vis;
private String value;
private String name;
private String idlName;
private boolean innerClassDecl;
private boolean constant;
private MemberDefinition member;
private boolean forceTransient;
/**
* Create a new Member object.
*/
public Member(MemberDefinition member,
String value,
ContextStack stack,
CompoundType enclosing) {
this.member = member;
this.value = value;
forceTransient = false;
innerClassDecl = member.getInnerClass() != null;
// If we are not an inner class, finish initializing now.
// Otherwise, wait until outer class is finished, then
// call init to avoid potential recursion problems...
if (!innerClassDecl) {
init (stack,enclosing);
}
}
public void init (ContextStack stack, CompoundType enclosing) {
constant = false;
name = member.getName().toString();
vis = getVisibilityString(member);
idlName = null;
// Add self to stack...
int contextCode = ContextStack.MEMBER;
stack.setNewContextCode(contextCode);
// Check for special contextCodes...
if (member.isVariable()) {
if (value != null && member.isConstant()) {
contextCode = ContextStack.MEMBER_CONSTANT;
this.constant = true;
} else if (member.isStatic()) {
contextCode = ContextStack.MEMBER_STATIC;
} else if (member.isTransient()) {
contextCode = ContextStack.MEMBER_TRANSIENT;
}
}
stack.setNewContextCode(contextCode);
stack.push(this);
type = makeType(member.getType(),null,stack);
if (type == null ||
(!innerClassDecl &&
!member.isStatic() &&
!member.isTransient() &&
!assertNotImpl(type,false,stack,enclosing,true))) {
stack.pop(false);
throw new CompilerError("");
}
// Clean up primitive constant values...
if (constant && type.isPrimitive()) {
if (type.isType(TYPE_LONG) || type.isType(TYPE_FLOAT) || type.isType(TYPE_DOUBLE)) {
int length = value.length();
char lastChar = value.charAt(length-1);
if (!Character.isDigit(lastChar)) {
this.value = value.substring(0,length-1);
}
} else if (type.isType(TYPE_BOOLEAN)) {
value = value.toUpperCase();
}
}
if (constant && type.isType(TYPE_STRING)) {
value = "L" + value;
}
stack.pop(true);
}
public void setIDLName (String name) {
this.idlName = name;
}
/**
* Cloning is supported by returning a shallow copy of this object.
*/
protected Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new Error("clone failed");
}
}
}
}