/* * 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 * {@code isIDLEntity() && isException()}. */ public boolean isIDLEntityException () { return isIDLEntity() && isException(); } /** * Return true if {@code 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. *
* 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