duke@1: /* ohair@158: * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved. duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@1: * duke@1: * This code is free software; you can redistribute it and/or modify it duke@1: * under the terms of the GNU General Public License version 2 only, as ohair@158: * published by the Free Software Foundation. Oracle designates this duke@1: * particular file as subject to the "Classpath" exception as provided ohair@158: * by Oracle in the LICENSE file that accompanied this code. duke@1: * duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@1: * version 2 for more details (a copy is included in the LICENSE file that duke@1: * accompanied this code). duke@1: * duke@1: * You should have received a copy of the GNU General Public License version duke@1: * 2 along with this work; if not, write to the Free Software Foundation, duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@1: * ohair@158: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@158: * or visit www.oracle.com if you need additional information or have any ohair@158: * questions. duke@1: */ duke@1: duke@1: /* duke@1: * Licensed Materials - Property of IBM duke@1: * RMI-IIOP v1.0 duke@1: * Copyright IBM Corp. 1998 1999 All Rights Reserved duke@1: * duke@1: */ duke@1: duke@1: package sun.rmi.rmic.iiop; duke@1: alanb@473: import java.util.Arrays; duke@1: import java.util.Vector; duke@1: import sun.tools.java.Identifier; duke@1: import sun.tools.java.ClassNotFound; duke@1: import sun.tools.java.ClassDefinition; duke@1: import sun.tools.java.ClassDeclaration; duke@1: import sun.tools.java.MemberDefinition; duke@1: import sun.tools.java.CompilerError; duke@1: import sun.tools.tree.Node; duke@1: import sun.tools.tree.LocalMember; duke@1: import sun.tools.tree.CharExpression; duke@1: import sun.tools.tree.IntegerExpression; duke@1: import sun.rmi.rmic.IndentingWriter; duke@1: import java.io.IOException; duke@1: import java.util.HashSet; duke@1: import java.util.Enumeration; duke@1: import java.io.File; duke@1: duke@1: /** duke@1: * A CompoundType is an abstract base class for all IIOP class and duke@1: * interface types. duke@1: * duke@1: * @author Bryan Atsatt duke@1: */ duke@1: public abstract class CompoundType extends Type { duke@1: duke@1: protected Method[] methods; duke@1: protected InterfaceType[] interfaces; duke@1: protected Member[] members; duke@1: protected ClassDefinition classDef; duke@1: protected ClassDeclaration classDecl; duke@1: duke@1: protected boolean isCORBAObject = false; duke@1: protected boolean isIDLEntity = false; duke@1: protected boolean isAbstractBase = false; duke@1: protected boolean isValueBase = false; duke@1: protected boolean isCORBAUserException = false; duke@1: protected boolean isException = false; duke@1: protected boolean isCheckedException = false; duke@1: protected boolean isRemoteExceptionOrSubclass = false; duke@1: protected String idlExceptionName; duke@1: protected String qualifiedIDLExceptionName; duke@1: duke@1: //_____________________________________________________________________ duke@1: // Public Interfaces duke@1: //_____________________________________________________________________ duke@1: duke@1: /** duke@1: * Return true if this type implements duke@1: * org.omg.CORBA.Object. duke@1: */ duke@1: public boolean isCORBAObject () { duke@1: return isCORBAObject; duke@1: } duke@1: duke@1: /** duke@1: * Return true if this type implements duke@1: * org.omg.CORBA.portable.IDLEntity. duke@1: */ duke@1: public boolean isIDLEntity () { duke@1: return isIDLEntity; duke@1: } duke@1: duke@1: /** duke@1: * Return true if this type implements duke@1: * org.omg.CORBA.portable.ValueBase. duke@1: */ duke@1: public boolean isValueBase () { duke@1: return isValueBase; duke@1: } duke@1: duke@1: /** duke@1: * Return true if this type is a CORBA duke@1: * abstract interface. duke@1: */ duke@1: public boolean isAbstractBase () { duke@1: return isAbstractBase; duke@1: } duke@1: duke@1: /** duke@1: * Return true if this type is an exception. duke@1: */ duke@1: public boolean isException () { duke@1: return isException; duke@1: } duke@1: duke@1: /** duke@1: * Return true if this type is a "checked" exception. duke@1: * Result if valid iff isException() returns true. duke@1: */ duke@1: public boolean isCheckedException () { duke@1: return isCheckedException; duke@1: } duke@1: duke@1: /** duke@1: * Return true if this type is a java.rmi.RemoteException duke@1: * or one of its subclasses. Result if valid iff isException() duke@1: * returns true. duke@1: */ duke@1: public boolean isRemoteExceptionOrSubclass () { duke@1: return isRemoteExceptionOrSubclass; duke@1: } duke@1: duke@1: /** duke@1: * Return true if this type is exactly duke@1: * org.omg.CORBA.UserException. duke@1: */ duke@1: public boolean isCORBAUserException () { duke@1: return isCORBAUserException; duke@1: } duke@1: duke@1: /** duke@1: * Return true if this type implements duke@1: * isIDLEntity() && isException(). duke@1: */ duke@1: public boolean isIDLEntityException () { duke@1: return isIDLEntity() && isException(); duke@1: } duke@1: /** duke@1: * Return true if isIDLEntity() && !isValueBase() duke@1: * && !isAbstractBase() && !isCORBAObject() duke@1: * && !isIDLEntityException(). duke@1: */ duke@1: public boolean isBoxed () { duke@1: return (isIDLEntity() && !isValueBase() && duke@1: !isAbstractBase() && !isCORBAObject() && duke@1: !isIDLEntityException()); duke@1: } duke@1: duke@1: /** duke@1: * If this type represents an exception, return the duke@1: * IDL name including the "Ex" mangling, otherwise duke@1: * return null. duke@1: */ duke@1: public String getIDLExceptionName () { duke@1: return idlExceptionName; duke@1: } duke@1: duke@1: /** duke@1: * If this type represents an exception, return the duke@1: * qualified IDL name including the "Ex" mangling, duke@1: * otherwise return null. duke@1: * @param global If true, prepends "::". duke@1: */ duke@1: public String getQualifiedIDLExceptionName (boolean global) { duke@1: if (qualifiedIDLExceptionName != null && duke@1: global && duke@1: getIDLModuleNames().length > 0) { duke@1: return IDL_NAME_SEPARATOR + qualifiedIDLExceptionName; duke@1: } else { duke@1: return qualifiedIDLExceptionName; duke@1: } duke@1: } duke@1: duke@1: /** duke@1: * Return signature for this type (e.g. com.acme.Dynamite duke@1: * would return "com.acme.Dynamite", byte = "B") duke@1: */ duke@1: public String getSignature() { duke@1: String sig = classDecl.getType().getTypeSignature(); duke@1: if (sig.endsWith(";")) { duke@1: sig = sig.substring(0,sig.length()-1); duke@1: } duke@1: return sig; duke@1: } duke@1: duke@1: /** duke@1: * Return the ClassDeclaration for this type. duke@1: */ duke@1: public ClassDeclaration getClassDeclaration() { duke@1: return classDecl; duke@1: } duke@1: duke@1: /** duke@1: * Return the ClassDefinition for this type. duke@1: */ duke@1: public ClassDefinition getClassDefinition() { duke@1: return classDef; duke@1: } duke@1: duke@1: /** duke@1: * Return the parent class of this type. Returns null if this duke@1: * type is an interface or if there is no parent. duke@1: */ duke@1: public ClassType getSuperclass() { duke@1: return null; duke@1: } duke@1: duke@1: /** duke@1: * Return an array of interfaces directly implemented by this type. duke@1: *
duke@1: * The order of the array returned is arbitrary.
duke@1: */
duke@1: public InterfaceType[] getInterfaces() {
duke@1: if( interfaces != null ) {
duke@1: return (InterfaceType[]) interfaces.clone();
duke@1: }
duke@1: return null;
duke@1: }
duke@1:
duke@1: /**
duke@1: * Return an array of Type.Method objects representing all
duke@1: * of the methods implemented directly by this type.
duke@1: */
duke@1: public Method[] getMethods() {
duke@1: if( methods != null ) {
duke@1: return (Method[]) methods.clone();
duke@1: }
duke@1: return null;
duke@1: }
duke@1:
duke@1: /**
duke@1: * Return an array of Type.Member objects representing all of
duke@1: * the data members directly implemented by this interface.
duke@1: */
duke@1: public Member[] getMembers() {
duke@1: if( members != null ) {
duke@1: return (Member[]) members.clone();
duke@1: }
duke@1: return null;
duke@1: }
duke@1:
duke@1: /**
duke@1: * Create a CompoundType object for the given class.
duke@1: *
duke@1: * If the class is not a properly formed or if some other error occurs, the
duke@1: * return value will be null, and errors will have been reported to the
duke@1: * supplied BatchEnvironment.
duke@1: */
duke@1: public static CompoundType forCompound (ClassDefinition classDef,
duke@1: ContextStack stack) {
duke@1: CompoundType result = null;
duke@1:
duke@1: try {
duke@1: result = (CompoundType) makeType(classDef.getType(),classDef,stack);
duke@1: } catch (ClassCastException e) {}
duke@1:
duke@1: return result;
duke@1: }
duke@1:
duke@1:
duke@1: //_____________________________________________________________________
duke@1: // Subclass/Internal Interfaces
duke@1: //_____________________________________________________________________
duke@1:
duke@1: /**
duke@1: * Release all resources.
duke@1: */
duke@1: protected void destroy () {
duke@1: if (!destroyed) {
duke@1: super.destroy();
duke@1:
duke@1: if (methods != null) {
duke@1: for (int i = 0; i < methods.length; i++) {
duke@1: if (methods[i] != null) methods[i].destroy();
duke@1: }
duke@1: methods = null;
duke@1: }
duke@1:
duke@1: if (interfaces != null) {
duke@1: for (int i = 0; i < interfaces.length; i++) {
duke@1: if (interfaces[i] != null) interfaces[i].destroy();
duke@1: }
duke@1: interfaces = null;
duke@1: }
duke@1:
duke@1: if (members != null) {
duke@1: for (int i = 0; i < members.length; i++) {
duke@1: if (members[i] != null) members[i].destroy();
duke@1: }
duke@1: members = null;
duke@1: }
duke@1:
duke@1: classDef = null;
duke@1: classDecl = null;
duke@1: }
duke@1: }
duke@1:
duke@1: /*
duke@1: * Load a Class instance. Return null if fail.
duke@1: */
duke@1: protected Class loadClass() {
duke@1:
duke@1: Class ourClass = null;
duke@1:
duke@1: // To avoid getting out-of-date Class instances, and
duke@1: // to ensure that there is an instance, we must compile
duke@1: // any classes that we've seen and which are not yet
duke@1: // compiled. We can't just compile this class, 'cuz it
duke@1: // may have dependencies on classes which have not been
duke@1: // compiled...
duke@1:
duke@1: try {
duke@1: env.getMain().compileAllClasses(env);
duke@1: } catch (Exception e1) {
duke@1: for (Enumeration e = env.getClasses() ; e.hasMoreElements() ; ) {
duke@1: ClassDeclaration c = (ClassDeclaration)e.nextElement();
duke@1: }
duke@1: failedConstraint(26,false,stack,"required classes");
duke@1: env.flushErrors();
duke@1: }
duke@1:
duke@1: // Now try to get the Class...
duke@1: // The outer try block is there for people who might want to use
duke@1: // the compiler at run-time of their AS.
duke@1: // They could set and use their own context class loader for loading
duke@1: // classes directly.
duke@1: try {
duke@1: ClassLoader cl = Thread.currentThread().getContextClassLoader();
duke@1: ourClass = cl.loadClass(getQualifiedName());
duke@1: } catch(ClassNotFoundException cfe) {
duke@1:
duke@1: try {
duke@1: ourClass = env.classPathLoader.loadClass(getQualifiedName());
duke@1: } catch (NullPointerException e) {
duke@1: // This should never happen
duke@1: } catch (ClassNotFoundException e) {
duke@1: // Fall through to the next case (which is to look in the
duke@1: // output directory for generated files)
duke@1: }
duke@1: }
duke@1:
duke@1: /* This piece of code used to cause the compiler to ignore jar files
duke@1: on its classpath
duke@1: try {
duke@1: ourClass = Util.loadClass(getQualifiedName(),null,null);
duke@1: } catch (ClassNotFoundException e) {
duke@1: } catch (LinkageError e) {
duke@1: }
duke@1: */
duke@1:
duke@1: if (ourClass == null) {
duke@1:
duke@1: // Try one last thing. If the class was compiled into
duke@1: // a directory that's not in the classpath, the load
duke@1: // will fail. Let's get the bits off the disk and load
duke@1: // it directly...
duke@1:
duke@1: if (env.loader == null) {
duke@1: File destDir = env.getMain().getDestinationDir();
duke@1: if (destDir == null) {
duke@1: destDir = new File(".");
duke@1: }
duke@1: env.loader = new DirectoryLoader(destDir);
duke@1: }
duke@1:
duke@1: try {
duke@1: ourClass = env.loader.loadClass(getQualifiedName());
duke@1: } catch (Exception e) {}
duke@1: }
duke@1:
duke@1: return ourClass;
duke@1: }
duke@1:
duke@1: // Print "extends XX"
duke@1:
duke@1: protected boolean printExtends (IndentingWriter writer,
duke@1: boolean useQualifiedNames,
duke@1: boolean useIDLNames,
duke@1: boolean globalIDLNames) throws IOException {
duke@1:
duke@1: ClassType parent = getSuperclass();
duke@1:
duke@1: if (parent != null && (!useIDLNames ||
duke@1: (!parent.isType(TYPE_ANY) && !parent.isType(TYPE_CORBA_OBJECT)))) {
duke@1: writer.p(" extends ");
duke@1: parent.printTypeName(writer,useQualifiedNames,useIDLNames,globalIDLNames);
duke@1: return true;
duke@1: }
duke@1: return false;
duke@1: }
duke@1:
duke@1: // Print "implements XX, YY"
duke@1:
duke@1: protected void printImplements (IndentingWriter writer,
duke@1: String prefix,
duke@1: boolean useQualifiedNames,
duke@1: boolean useIDLNames,
duke@1: boolean globalIDLNames) throws IOException {
duke@1:
duke@1: InterfaceType[] interfaces = getInterfaces();
duke@1:
duke@1: String adjective = " implements";
duke@1:
duke@1: if (isInterface()) {
duke@1: adjective = " extends";
duke@1: }
duke@1:
duke@1: if (useIDLNames) {
duke@1: adjective = ":";
duke@1: }
duke@1:
duke@1: for (int i = 0; i < interfaces.length; i++) {
duke@1: if (!useIDLNames || (!interfaces[i].isType(TYPE_ANY) && !interfaces[i].isType(TYPE_CORBA_OBJECT))) {
duke@1: if (i == 0) {
duke@1: writer.p(prefix + adjective + " ");
duke@1: } else {
duke@1: writer.p(", ");
duke@1: }
duke@1: interfaces[i].printTypeName(writer,useQualifiedNames,useIDLNames,globalIDLNames);
duke@1: }
duke@1: }
duke@1: }
duke@1:
duke@1: // Print members
duke@1:
duke@1: protected void printMembers ( IndentingWriter writer,
duke@1: boolean useQualifiedNames,
duke@1: boolean useIDLNames,
duke@1: boolean globalIDLNames) throws IOException {
duke@1:
duke@1: CompoundType.Member[] members = getMembers();
duke@1:
duke@1: for (int i = 0; i < members.length; i++) {
duke@1: if (!members[i].isInnerClassDeclaration()) {
duke@1: Type it = members[i].getType();
duke@1: String visibility = members[i].getVisibility();
duke@1: String name;
duke@1:
duke@1: if (useIDLNames) {
duke@1: name = members[i].getIDLName();
duke@1: } else {
duke@1: name = members[i].getName();
duke@1: }
duke@1:
duke@1: String value = members[i].getValue();
duke@1:
duke@1: writer.p(visibility);
duke@1: if (visibility.length() > 0) {
duke@1: writer.p(" ");
duke@1: }
duke@1: it.printTypeName(writer,useQualifiedNames,useIDLNames,globalIDLNames);
duke@1: writer.p(" " + name);
duke@1:
duke@1: if (value != null) {
duke@1: writer.pln(" = " + value + ";");
duke@1: } else {
duke@1: writer.pln(";");
duke@1: }
duke@1: }
duke@1: }
duke@1: }
duke@1:
duke@1: // Print methods
duke@1:
duke@1: protected void printMethods ( IndentingWriter writer,
duke@1: boolean useQualifiedNames,
duke@1: boolean useIDLNames,
duke@1: boolean globalIDLNames) throws IOException {
duke@1:
duke@1: CompoundType.Method[] methods = getMethods();
duke@1:
duke@1: for (int m = 0; m < methods.length; m++) {
duke@1: CompoundType.Method theMethod = methods[m];
duke@1: printMethod(theMethod,writer,useQualifiedNames,useIDLNames,globalIDLNames);
duke@1: }
duke@1: }
duke@1:
duke@1: // Print a method...
duke@1:
duke@1: protected void printMethod (CompoundType.Method it,
duke@1: IndentingWriter writer,
duke@1: boolean useQualifiedNames,
duke@1: boolean useIDLNames,
duke@1: boolean globalIDLNames) throws IOException {
duke@1:
duke@1:
duke@1: // Write visibility...
duke@1:
duke@1: String visibility = it.getVisibility();
duke@1:
duke@1: writer.p(visibility);
duke@1: if (visibility.length() > 0) {
duke@1: writer.p(" ");
duke@1: }
duke@1:
duke@1: // Write return type...
duke@1:
duke@1: it.getReturnType().printTypeName(writer,useQualifiedNames,useIDLNames,globalIDLNames);
duke@1:
duke@1: // Write method name...
duke@1:
duke@1: if (useIDLNames) {
duke@1: writer.p(" " + it.getIDLName());
duke@1: } else {
duke@1: writer.p(" " + it.getName());
duke@1: }
duke@1:
duke@1: // Write arguments...
duke@1:
duke@1: writer.p(" (");
duke@1: Type[] args = it.getArguments();
duke@1: String[] argNames = it.getArgumentNames();
duke@1:
duke@1: for (int i = 0; i < args.length; i++) {
duke@1: if (i > 0) {
duke@1: writer.p(", ");
duke@1: }
duke@1:
duke@1: if (useIDLNames) {
duke@1: writer.p("in ");
duke@1: }
duke@1:
duke@1: args[i].printTypeName(writer,useQualifiedNames,useIDLNames,globalIDLNames);
duke@1: writer.p(" " + argNames[i]);
duke@1: }
duke@1: writer.p(")");
duke@1:
duke@1: // Write exceptions...
duke@1:
duke@1: ClassType[] exceptions;
duke@1:
duke@1: if (isType(TYPE_IMPLEMENTATION)) {
duke@1: exceptions = it.getImplExceptions();
duke@1: } else {
duke@1: exceptions = it.getExceptions();
duke@1: }
duke@1:
duke@1: for (int i = 0; i < exceptions.length; i++) {
duke@1: if (i == 0) {
duke@1: if (useIDLNames) {
duke@1: writer.p(" raises (");
duke@1: } else {
duke@1: writer.p(" throws ");
duke@1: }
duke@1: } else {
duke@1: writer.p(", ");
duke@1: }
duke@1:
duke@1: if (useIDLNames) {
duke@1: if (useQualifiedNames) {
duke@1: writer.p(exceptions[i].getQualifiedIDLExceptionName(globalIDLNames));
duke@1: } else {
duke@1: writer.p(exceptions[i].getIDLExceptionName());
duke@1: }
duke@1: writer.p(" [a.k.a. ");
duke@1: exceptions[i].printTypeName(writer,useQualifiedNames,useIDLNames,globalIDLNames);
duke@1: writer.p("]");
duke@1: } else {
duke@1: exceptions[i].printTypeName(writer,useQualifiedNames,useIDLNames,globalIDLNames);
duke@1: }
duke@1: }
duke@1:
duke@1: if (useIDLNames && exceptions.length > 0) {
duke@1: writer.p(")");
duke@1: }
duke@1:
duke@1: if (it.isInherited()) {
duke@1: writer.p(" // Inherited from ");
duke@1: writer.p(it.getDeclaredBy());
duke@1: }
duke@1:
duke@1: writer.pln(";");
duke@1: }
duke@1:
duke@1: /**
duke@1: * Create a CompoundType instance for the given class. NOTE: This constructor
duke@1: * is ONLY for SpecialClassType and SpecialInterfaceType.
duke@1: */
duke@1: protected CompoundType(ContextStack stack, int typeCode, ClassDefinition classDef) {
duke@1: super(stack,typeCode);
duke@1: this.classDef = classDef;
duke@1: classDecl = classDef.getClassDeclaration();
duke@1: interfaces = new InterfaceType[0];
duke@1: methods = new Method[0];
duke@1: members = new Member[0];
duke@1:
duke@1: // If we are an inner class/interface, reset the type codes...
duke@1:
duke@1: if (classDef.isInnerClass()) {
duke@1: setTypeCode(typeCode | TM_INNER);
duke@1: }
duke@1:
duke@1: // Set special flags...
duke@1:
duke@1: setFlags();
duke@1: }
duke@1:
duke@1: private void setFlags() {
duke@1:
duke@1: try {
duke@1:
duke@1: // Set our special interface flags...
duke@1:
duke@1: isCORBAObject = env.defCorbaObject.implementedBy(env,classDecl);
duke@1: isIDLEntity = env.defIDLEntity.implementedBy(env,classDecl);
duke@1: isValueBase = env.defValueBase.implementedBy(env,classDecl);
duke@1: isAbstractBase = isInterface() && // Interface, not a class.
duke@1: isIDLEntity && // Implements IDLEntity.
duke@1: !isValueBase && // Does not implement ValueBase.
duke@1: !isCORBAObject; // Does not implement org.omg.CORBA.Object;
duke@1: isCORBAUserException = (classDecl.getName() == idCorbaUserException);
duke@1:
duke@1: // Is this an exception?
duke@1:
duke@1: if (env.defThrowable.implementedBy(env, classDecl)) {
duke@1:
duke@1: // Yes...
duke@1:
duke@1: isException = true;
duke@1:
duke@1: // Is it a checked exception?
duke@1:
duke@1: if (env.defRuntimeException.implementedBy(env,classDecl) ||
duke@1: env.defError.implementedBy(env,classDecl)) {
duke@1: isCheckedException = false;
duke@1: } else {
duke@1: isCheckedException = true;
duke@1: }
duke@1:
duke@1: // Is it java.rmi.RemoteException or a subclass?
duke@1:
duke@1: if (env.defRemoteException.implementedBy(env,classDecl)) {
duke@1: isRemoteExceptionOrSubclass = true;
duke@1: } else {
duke@1: isRemoteExceptionOrSubclass = false;
duke@1: }
duke@1: } else {
duke@1: isException = false;
duke@1: }
duke@1: } catch (ClassNotFound e) {
duke@1: classNotFound(stack,e);
duke@1: }
duke@1: }
duke@1:
duke@1: /**
duke@1: * Create a CompoundType instance for the given class. The resulting
duke@1: * object is not yet completely initialized.
duke@1: */
duke@1: protected CompoundType(ContextStack stack, ClassDefinition classDef,
duke@1: int typeCode) {
duke@1: super(stack,typeCode);
duke@1: this.classDef = classDef;
duke@1: classDecl = classDef.getClassDeclaration();
duke@1:
duke@1: // If we are an inner class/interface, reset the type codes...
duke@1:
duke@1: if (classDef.isInnerClass()) {
duke@1: setTypeCode(typeCode | TM_INNER);
duke@1: }
duke@1:
duke@1: // Set special flags...
duke@1:
duke@1: setFlags();
duke@1:
duke@1: // Set names...
duke@1:
duke@1: Identifier id = classDef.getName();
duke@1: String idlName;
duke@1: String[] idlModuleNames;
duke@1:
duke@1: try {
duke@1:
duke@1: // These can fail if we get case-sensitive name matches...
duke@1:
duke@1: idlName = IDLNames.getClassOrInterfaceName(id,env);
duke@1: idlModuleNames = IDLNames.getModuleNames(id,isBoxed(),env);
duke@1:
duke@1: setNames(id,idlModuleNames,idlName);
duke@1:
duke@1: // Is this an exception?
duke@1:
duke@1: if (isException()) {
duke@1:
duke@1: // Yes, so set our mangled exception names...
duke@1:
duke@1: isException = true;
duke@1: idlExceptionName = IDLNames.getExceptionName(getIDLName());
duke@1: qualifiedIDLExceptionName =
duke@1: IDLNames.getQualifiedName(getIDLModuleNames(),idlExceptionName);
duke@1: }
duke@1:
duke@1: // Set interfaces, methods and members...
duke@1:
duke@1: interfaces = null; // set in initialize()
duke@1: methods = null; // set in initialize()
duke@1: members = null; // set in initialize()
duke@1:
duke@1: } catch (Exception e) {
duke@1: failedConstraint(7,false,stack,id.toString(),e.getMessage());
duke@1: throw new CompilerError("");
duke@1: }
duke@1: }
duke@1:
duke@1: /**
duke@1: * Initialize this instance.
duke@1: */
duke@1: protected boolean initialize ( Vector directInterfaces,
duke@1: Vector directMethods,
duke@1: Vector directMembers,
duke@1: ContextStack stack,
duke@1: boolean quiet) {
duke@1:
duke@1: boolean result = true;
duke@1:
duke@1: // Initialize our arrays...
duke@1:
duke@1: if (directInterfaces != null && directInterfaces.size() > 0) {
duke@1: interfaces = new InterfaceType[directInterfaces.size()];
duke@1: directInterfaces.copyInto(interfaces);
duke@1: } else {
duke@1: interfaces = new InterfaceType[0];
duke@1: }
duke@1:
duke@1: if (directMethods != null && directMethods.size() > 0) {
duke@1: methods = new Method[directMethods.size()];
duke@1: directMethods.copyInto(methods);
duke@1:
duke@1: // Now set the idl names for each...
duke@1:
duke@1: try {
duke@1: IDLNames.setMethodNames(this, methods,env);
duke@1: } catch (Exception e) {
duke@1: failedConstraint(13,quiet,stack,getQualifiedName(),e.getMessage());
duke@1: result = false;
duke@1: }
duke@1:
duke@1: } else {
duke@1: methods = new Method[0];
duke@1: }
duke@1:
duke@1: if (directMembers != null && directMembers.size() > 0) {
duke@1: members = new Member[directMembers.size()];
duke@1: directMembers.copyInto(members);
duke@1:
duke@1: // If we have any un-initialized inner classes, now is the time
duke@1: // to init them...
duke@1:
duke@1: for (int i = 0; i < members.length; i++) {
duke@1: if (members[i].isInnerClassDeclaration()) {
duke@1: try {
duke@1: members[i].init(stack,this);
duke@1: } catch (CompilerError e) {
duke@1: return false;
duke@1: }
duke@1: }
duke@1: }
duke@1:
duke@1: // Now set the idl names for each...
duke@1:
duke@1: try {
duke@1: IDLNames.setMemberNames(this, members,methods,env);
duke@1: } catch (Exception e) {
duke@1: int constraint = classDef.isInterface() ? 19 : 20;
duke@1: failedConstraint(constraint,quiet,stack,getQualifiedName(),e.getMessage());
duke@1: result = false;
duke@1: }
duke@1:
duke@1: } else {
duke@1: members = new Member[0];
duke@1: }
duke@1:
duke@1: // Set our repositoryID...
duke@1:
duke@1: if (result) {
duke@1: result = setRepositoryID();
duke@1: }
duke@1:
duke@1: return result;
duke@1: }
duke@1:
duke@1: /*
duke@1: * Return Type or null if error. classDef may be null.
duke@1: */
duke@1: protected static Type makeType (sun.tools.java.Type theType,
duke@1: ClassDefinition classDef,
duke@1: ContextStack stack) {
duke@1:
duke@1: if (stack.anyErrors()) return null;
duke@1:
duke@1: // See if we can find this type in the cache. If so, return it...
duke@1:
duke@1: String key = theType.toString();
duke@1:
duke@1: Type result = getType(key,stack);
duke@1:
duke@1: if (result != null) {
duke@1: return result;
duke@1: }
duke@1:
duke@1: // Gotta try with context...
duke@1:
duke@1: result = getType(key + stack.getContextCodeString(),stack);
duke@1:
duke@1: if (result != null) {
duke@1: return result;
duke@1: }
duke@1:
duke@1: // Gotta map it...
duke@1:
duke@1: BatchEnvironment env = stack.getEnv();
duke@1: int typeCode = theType.getTypeCode();
duke@1: switch (typeCode) {
duke@1: case TC_BOOLEAN:
duke@1: case TC_BYTE:
duke@1: case TC_CHAR:
duke@1: case TC_SHORT:
duke@1: case TC_INT:
duke@1: case TC_LONG:
duke@1: case TC_FLOAT:
duke@1: case TC_DOUBLE:
duke@1: {
duke@1: // Primitive...
duke@1:
duke@1: result = PrimitiveType.forPrimitive(theType,stack);
duke@1: break;
duke@1: }
duke@1:
duke@1: case TC_ARRAY:
duke@1: {
duke@1: // Array.
duke@1:
duke@1: result = ArrayType.forArray(theType,stack);
duke@1: break;
duke@1: }
duke@1:
duke@1: case TC_CLASS:
duke@1: {
duke@1: try {
duke@1: // First, make sure we have the class definition...
duke@1:
duke@1: ClassDefinition theClass = classDef;
duke@1:
duke@1: if (theClass == null) {
duke@1: theClass = env.getClassDeclaration(theType).getClassDefinition(env);
duke@1: }
duke@1:
duke@1: // Is it an interface or a class?
duke@1:
duke@1: if (theClass.isInterface()) {
duke@1:
duke@1: // An interface. Is it a special case?
duke@1:
duke@1: result = SpecialInterfaceType.forSpecial(theClass,stack);
duke@1:
duke@1: if (result == null) {
duke@1:
duke@1: // No, does it implement java.rmi.Remote?
duke@1:
duke@1: if (env.defRemote.implementedBy(env,theClass.getClassDeclaration())) {
duke@1:
duke@1: // Yep, so just see if we can create an instance of RemoteType
duke@1: // from it...
duke@1:
duke@1: boolean parentIsValue = stack.isParentAValue();
duke@1: result = RemoteType.forRemote(theClass,stack,parentIsValue);
duke@1:
duke@1: // If we did not succeed AND we are in a value context, then
duke@1: // go ahead and make an NC type out of it...
duke@1:
duke@1: if (result == null && parentIsValue) {
duke@1: result = NCInterfaceType.forNCInterface(theClass,stack);
duke@1: }
duke@1: } else {
duke@1:
duke@1: // Nope, is it an AbstractType?
duke@1:
duke@1: result = AbstractType.forAbstract(theClass,stack,true);
duke@1:
duke@1: if (result == null) {
duke@1:
duke@1: // No, so treat it as a non-conforming interface type...
duke@1:
duke@1: result = NCInterfaceType.forNCInterface(theClass,stack);
duke@1: }
duke@1: }
duke@1: }
duke@1: } else {
duke@1:
duke@1: // A class. Is it a special case?
duke@1:
duke@1: result = SpecialClassType.forSpecial(theClass,stack);
duke@1:
duke@1: if (result == null) {
duke@1:
duke@1: ClassDeclaration classDecl = theClass.getClassDeclaration();
duke@1:
duke@1: // Nope, does it implement java.rmi.Remote?
duke@1:
duke@1: if (env.defRemote.implementedBy(env,classDecl)) {
duke@1:
duke@1: // Yep, so just see if we can create an instance of
duke@1: // ImplementationType from it...
duke@1:
duke@1: boolean parentIsValue = stack.isParentAValue();
duke@1: result = ImplementationType.forImplementation(theClass,stack,parentIsValue);
duke@1:
duke@1: // If we did not succeed AND inValue is true, then
duke@1: // go ahead and make an NC type out of it...
duke@1:
duke@1: if (result == null && parentIsValue) {
duke@1: result = NCClassType.forNCClass(theClass,stack);
duke@1: }
duke@1: } else {
duke@1:
duke@1: // No, does it implement Serializable?
duke@1:
duke@1: if (env.defSerializable.implementedBy(env,classDecl)) {
duke@1:
duke@1: // Yep, so just see if we can create an instance of ValueType
duke@1: // from it...
duke@1:
duke@1: result = ValueType.forValue(theClass,stack,true);
duke@1: }
duke@1:
duke@1: if (result == null) {
duke@1:
duke@1: // Treat it as a non-conforming class type...
duke@1:
duke@1: result = NCClassType.forNCClass(theClass,stack);
duke@1: }
duke@1: }
duke@1: }
duke@1: }
duke@1: } catch (ClassNotFound e) {
duke@1: classNotFound(stack,e);
duke@1: }
duke@1: break;
duke@1: }
duke@1:
duke@1: default: throw new CompilerError("Unknown typecode (" + typeCode + ") for " + theType.getTypeSignature());
duke@1: }
duke@1:
duke@1: return result;
duke@1: }
duke@1:
duke@1: /*
duke@1: * Check if exception is RemoteException or one of its parents.
duke@1: */
duke@1: public static boolean isRemoteException (ClassType ex,
duke@1: BatchEnvironment env) {
duke@1: sun.tools.java.Type exceptionType = ex.getClassDeclaration().getType();
duke@1:
duke@1: if (exceptionType.equals(env.typeRemoteException) ||
duke@1: exceptionType.equals(env.typeIOException) ||
duke@1: exceptionType.equals(env.typeException) ||
duke@1: exceptionType.equals(env.typeThrowable)) {
duke@1:
duke@1: return true;
duke@1: }
duke@1: return false;
duke@1: }
duke@1:
duke@1: /*
duke@1: * Check if method is conforming.
duke@1: */
duke@1: protected boolean isConformingRemoteMethod (Method method, boolean quiet)
duke@1: throws ClassNotFound {
duke@1:
duke@1: // Do we have one exception that is RemoteException or
duke@1: // a superclass of RemoteException?
duke@1:
duke@1: boolean haveRemote = false;
duke@1: ClassType[] exceptions = method.getExceptions();
duke@1:
duke@1: for (int i = 0; i < exceptions.length; i++) {
duke@1:
duke@1: // Is it a conforming exception?
duke@1:
duke@1: if (isRemoteException(exceptions[i],env)) {
duke@1:
duke@1: // Got it.
duke@1:
duke@1: haveRemote = true;
duke@1: break;
duke@1: }
duke@1: }
duke@1:
duke@1: // Do we have our exception?
duke@1:
duke@1: if (!haveRemote) {
duke@1:
duke@1: // No, so report failure...
duke@1:
duke@1: failedConstraint(5,quiet,stack,method.getEnclosing(), method.toString());
duke@1: }
duke@1:
duke@1: // Are any of the arguments exceptions which implement IDLEntity?
duke@1: // If so, report failure...
duke@1:
duke@1: boolean noIDLEntity = !isIDLEntityException(method.getReturnType(),method,quiet);
duke@1: if (noIDLEntity) {
duke@1: Type[] args = method.getArguments();
duke@1: for (int i = 0; i < args.length; i++) {
duke@1: if (isIDLEntityException(args[i],method,quiet)) {
duke@1: noIDLEntity = false;
duke@1: break;
duke@1: }
duke@1: }
duke@1: }
duke@1:
duke@1: return (haveRemote && noIDLEntity);
duke@1: }
duke@1:
duke@1: protected boolean isIDLEntityException(Type type, CompoundType.Method method,boolean quiet)
duke@1: throws ClassNotFound {
duke@1: if (type.isArray()) {
duke@1: type = type.getElementType();
duke@1: }
duke@1: if (type.isCompound()){
duke@1: if (((CompoundType)type).isIDLEntityException()) {
duke@1: failedConstraint(18,quiet,stack,method.getEnclosing(), method.toString());
duke@1: return true;
duke@1: }
duke@1: }
duke@1: return false;
duke@1: }
duke@1:
duke@1: /**
duke@1: * Convert all invalid types to valid ones.
duke@1: */
duke@1: protected void swapInvalidTypes () {
duke@1:
duke@1: // Walk all interfaces and check them...
duke@1:
duke@1: for (int i = 0; i < interfaces.length; i++) {
duke@1: if (interfaces[i].getStatus() != STATUS_VALID) {
duke@1: interfaces[i] = (InterfaceType)getValidType(interfaces[i]);
duke@1: }
duke@1: }
duke@1:
duke@1: // Update methods...
duke@1:
duke@1: for (int i = 0; i < methods.length; i++) {
duke@1: methods[i].swapInvalidTypes();
duke@1: }
duke@1:
duke@1: // Update members...
duke@1:
duke@1: for (int i = 0; i < members.length; i++) {
duke@1: members[i].swapInvalidTypes();
duke@1: }
duke@1: }
duke@1:
duke@1: /*
duke@1: * Add matching types to list. Return true if this type has not
duke@1: * been previously checked, false otherwise.
duke@1: */
duke@1: protected boolean addTypes (int typeCodeFilter,
duke@1: HashSet checked,
duke@1: Vector matching) {
duke@1:
duke@1: // Check self.
duke@1:
duke@1: boolean result = super.addTypes(typeCodeFilter,checked,matching);
duke@1:
duke@1: // Have we been checked before?
duke@1:
duke@1: if (result) {
duke@1:
duke@1: // Nope, so walk parent(s) and check them...
duke@1:
duke@1: ClassType parent = getSuperclass();
duke@1:
duke@1: if (parent != null) {
duke@1: parent.addTypes(typeCodeFilter,checked,matching);
duke@1: }
duke@1:
duke@1: // Walk all interfaces and check them...
duke@1:
duke@1: //if (interfaces == null) System.out.println("NULL for " +getQualifiedName() + " interfaces");
duke@1: for (int i = 0; i < interfaces.length; i++) {
duke@1:
duke@1: // Now recurse and add it and any referenced types...
duke@1:
duke@1: //if (interfaces[i] == null) System.out.println("NULL for " +getQualifiedName() + " interfaces[" + i + "]");
duke@1: interfaces[i].addTypes(typeCodeFilter,checked,matching);
duke@1: }
duke@1:
duke@1: // Walk all methods and check arguments...
duke@1:
duke@1: //if (methods == null) System.out.println("NULL for " +getQualifiedName() + " methods");
duke@1: for (int i = 0; i < methods.length; i++) {
duke@1:
duke@1: // Add return type...
duke@1: //if (methods[i] == null) System.out.println("NULL for " +getQualifiedName() + " methods[" + i + "]");
duke@1: //if (methods[i].getReturnType() == null) System.out.println("NULL for " +getQualifiedName() + methods[i]);
duke@1: methods[i].getReturnType().addTypes(typeCodeFilter,checked,matching);
duke@1:
duke@1: // Add args...
duke@1:
duke@1: Type[] args = methods[i].getArguments();
duke@1: //if (args == null) System.out.println("NULL for " + getQualifiedName() + " args");
duke@1:
duke@1: for (int j = 0; j < args.length; j++) {
duke@1:
duke@1: Type arg = args[j];
duke@1: //if (arg == null) System.out.println("NULL for " + getQualifiedName() + " arg[" +j+"]");
duke@1:
duke@1: // Add argument...
duke@1:
duke@1: arg.addTypes(typeCodeFilter,checked,matching);
duke@1: }
duke@1:
duke@1: // Add exceptions...
duke@1:
duke@1: ClassType[] exceptions = methods[i].getExceptions();
duke@1: //if (exceptions == null) System.out.println("NULL for " + getQualifiedName() + " exceptions");
duke@1:
duke@1: for (int j = 0; j < exceptions.length; j++) {
duke@1:
duke@1: ClassType ex = exceptions[j];
duke@1:
duke@1: // Add argument...
duke@1:
duke@1: ex.addTypes(typeCodeFilter,checked,matching);
duke@1: }
duke@1: }
duke@1:
duke@1: // Walk all members and add em...
duke@1:
duke@1: //if (members == null) System.out.println("NULL for " +getQualifiedName() + " members");
duke@1: for (int i = 0; i < members.length; i++) {
duke@1: //if (members[i] == null) System.out.println("NULL for " +getQualifiedName() + " members[" + i + "]");
duke@1: Type cType = members[i].getType();
duke@1: //if (cType == null) System.out.println("NULL for " + getQualifiedName() + " cType");
duke@1:
duke@1: // Add it...
duke@1:
duke@1: cType.addTypes(typeCodeFilter,checked,matching);
duke@1: }
duke@1: }
duke@1:
duke@1: return result;
duke@1: }
duke@1:
duke@1: /*
duke@1: * Return true if theType is a conforming constant type.
duke@1: */
duke@1: private boolean isConformingConstantType (MemberDefinition member) {
duke@1: return isConformingConstantType(member.getType(),member);
duke@1: }
duke@1:
duke@1: /*
duke@1: * Return true if theType is a conforming constant type.
duke@1: */
duke@1: private boolean isConformingConstantType (sun.tools.java.Type theType,MemberDefinition member) {
duke@1:
duke@1: // Constraint 3: Constants must be either primitives or String.
duke@1:
duke@1: boolean result = true;
duke@1: int typeCode = theType.getTypeCode();
duke@1: switch (typeCode) {
duke@1: case TC_BOOLEAN:
duke@1: case TC_BYTE:
duke@1: case TC_CHAR:
duke@1: case TC_SHORT:
duke@1: case TC_INT:
duke@1: case TC_LONG:
duke@1: case TC_FLOAT:
duke@1: case TC_DOUBLE: // Primitive, so OK...
duke@1: {
duke@1: break;
duke@1: }
duke@1:
duke@1: case TC_CLASS: // Must be java.lang.String
duke@1: {
duke@1: if (theType.getClassName() != idJavaLangString) {
duke@1: failedConstraint(3,false,stack,member.getClassDefinition(),member.getName());
duke@1: result = false;
duke@1: }
duke@1: break;
duke@1: }
duke@1:
duke@1: case TC_ARRAY: // Array constants are not allowed.
duke@1: {
duke@1: failedConstraint(3,false,stack,member.getClassDefinition(),member.getName());
duke@1: result = false;
duke@1: break;
duke@1: }
duke@1:
duke@1: default:
duke@1: throw new Error("unexpected type code: " + typeCode);
duke@1: }
duke@1:
duke@1: return result;
duke@1: }
duke@1:
duke@1:
duke@1: /*
duke@1: * Update any method from 'currentMethods' which is defined in a
duke@1: * parent class so that it's 'declaredBy' field specifies the
duke@1: * parent.
duke@1: * @param current The class or interface to gather methods from.
duke@1: * @param currentMethods The list into which to put the methods.
duke@1: * for contraint 6.
duke@1: * @param quiet true if silent errors.
duke@1: * @param stack the context stack.
duke@1: * @return currentMethods or null if failed a constraint check.
duke@1: */
duke@1: protected Vector updateParentClassMethods(ClassDefinition current,
duke@1: Vector currentMethods,
duke@1: boolean quiet,
duke@1: ContextStack stack)
duke@1: throws ClassNotFound {
duke@1:
duke@1: ClassDeclaration parentDecl = current.getSuperClass(env);
duke@1:
duke@1: while (parentDecl != null) {
duke@1:
duke@1: ClassDefinition parentDef = parentDecl.getClassDefinition(env);
duke@1: Identifier currentID = parentDecl.getName();
duke@1:
duke@1: if ( currentID == idJavaLangObject ) break;
duke@1:
duke@1: // Walk all members of this class and update any that
duke@1: // already exist in currentMethods...
duke@1:
duke@1: for (MemberDefinition member = parentDef.getFirstMember();
duke@1: member != null;
duke@1: member = member.getNextMember()) {
duke@1:
duke@1: if (member.isMethod() &&
duke@1: !member.isInitializer() &&
duke@1: !member.isConstructor() &&
duke@1: !member.isPrivate()) {
duke@1:
duke@1: // It's a method. Is it valid?
duke@1:
duke@1: Method method;
duke@1: try {
duke@1: method = new Method((CompoundType)this,member,quiet,stack);
duke@1: } catch (Exception e) {
duke@1: // Don't report anything here, it's already been reported...
duke@1: return null;
duke@1: }
duke@1:
duke@1: // Have we already seen it?
duke@1:
duke@1: int index = currentMethods.indexOf(method);
duke@1: if (index >= 0) {
duke@1:
duke@1: // Yes, so update it...
duke@1:
duke@1: Method currentMethod = (Method)currentMethods.elementAt(index);
duke@1: currentMethod.setDeclaredBy(currentID);
duke@1: }
duke@1: else currentMethods.addElement(method);
duke@1: }
duke@1: }
duke@1:
duke@1: // Update parent and keep walking up the chain...
duke@1:
duke@1: parentDecl = parentDef.getSuperClass(env);
duke@1: }
duke@1:
duke@1: return currentMethods;
duke@1: }
duke@1:
duke@1: /*
duke@1: * Add all of the public and protected methods defined in
duke@1: * current (other than initializers) to allMethods. If a sub-interface
duke@1: * re-declares an inherited method, it will not be added.
duke@1: * @param current The class or interface to gather methods from.
duke@1: * @param directMethods The list into which to put the methods.
duke@1: * @param noMultiInheritedMethods A flag to enable/disable checking
duke@1: * for contraint 6.
duke@1: * @param quiet true if silent errors.
duke@1: * @param stack the context stack.
duke@1: * @return directMethods or null if failed a constraint check.
duke@1: */
duke@1: protected Vector addAllMethods (ClassDefinition current, Vector directMethods,
duke@1: boolean noMultiInheritedMethods,
duke@1: boolean quiet,
duke@1: ContextStack stack)
duke@1: throws ClassNotFound {
duke@1:
duke@1: // Constraint 6: Multiple inherited interfaces may not
duke@1: // declare the same method.
duke@1:
duke@1: ClassDeclaration[] interfaces = current.getInterfaces();
duke@1:
duke@1: // We want to add members starting at the _least_ derived
duke@1: // interfaces. To do so, recurse until we have no more
duke@1: // interfaces...
duke@1:
duke@1: for (int i = 0; i < interfaces.length; i++) {
duke@1:
duke@1: Vector result = addAllMethods(interfaces[i].getClassDefinition(env),
duke@1: directMethods,
duke@1: noMultiInheritedMethods,quiet,stack);
duke@1: if (result == null) {
duke@1: return null;
duke@1: }
duke@1: }
duke@1:
duke@1: // Walk all members of this interface, adding any unique methods
duke@1: // other than initializers and private methods...
duke@1:
duke@1: for (MemberDefinition member = current.getFirstMember();
duke@1: member != null;
duke@1: member = member.getNextMember())
duke@1: {
duke@1: if (member.isMethod() &&
duke@1: !member.isInitializer() &&
duke@1: !member.isPrivate()) {
duke@1:
duke@1: // It's a method. Is it valid?
duke@1:
duke@1: Method method;
duke@1: try {
duke@1: method = new Method((CompoundType)this,member,quiet,stack);
duke@1: } catch (Exception e) {
duke@1: // Don't report anything here, it's already been reported...
duke@1: return null;
duke@1: }
duke@1:
duke@1: // Have we already seen it?
duke@1:
duke@1: if (!directMethods.contains(method)) {
duke@1:
duke@1: // Nope, so add it...
duke@1:
duke@1: directMethods.addElement(method);
duke@1:
duke@1: } else {
duke@1:
duke@1: // Yes. This is an error unless we are looking at the
duke@1: // target interface (or this is a ValueType). Are we?
duke@1:
duke@1: if (noMultiInheritedMethods && current != classDef &&
duke@1: !stack.isParentAValue() && !stack.getContext().isValue()) {
duke@1:
duke@1: // Nope. Say so and signal error by returning null..
duke@1:
duke@1: Method existingMethod = (Method) directMethods.elementAt(directMethods.indexOf(method));
duke@1: ClassDefinition existingMemberClassDef = existingMethod.getMemberDefinition().getClassDefinition();
duke@1:
duke@1: // There are more legal cases to consider here.
duke@1: // If the two methods belong to interfaces that inherit from each other
duke@1: // then it is just a redefinition which is legal.
duke@1: if ( current != existingMemberClassDef &&
duke@1: ! inheritsFrom(current, existingMemberClassDef) &&
duke@1: ! inheritsFrom(existingMemberClassDef, current))
duke@1: {
duke@1: //Identifier int1 = existingMethod.getEnclosing().getIdentifier();
duke@1: //Identifier int2 = current.getName();
duke@1: //String message = int1.toString() + " and " + int2.toString();
duke@1: String message = existingMemberClassDef.getName() + " and " + current.getName();
duke@1: failedConstraint(6,quiet,stack,classDef,message,method);
duke@1: return null;
duke@1: }
duke@1: }
duke@1:
duke@1: // Bug fix 5014329
duke@1:
duke@1: // find a matching method.
duke@1: int index = directMethods.indexOf(method);
duke@1: Method other = (Method) directMethods.get(index);
duke@1:
duke@1: // merge the two methods, such that the new method
duke@1: // will contain only those exception that can be thrown
duke@1: // by both these methods, not just one of them.
duke@1: Method newMethod = method.mergeWith(other);
duke@1:
duke@1: // replace the old method with the new.
duke@1: directMethods.set(index, newMethod);
duke@1: }
duke@1: }
duke@1: }
duke@1:
duke@1: return directMethods;
duke@1: }
duke@1:
duke@1: // This should really be a method on ClassDefinition, but it takes too long to change the shared source.
duke@1: // Works for both, classes and interfaces.
duke@1: protected boolean inheritsFrom(ClassDefinition def, ClassDefinition otherDef) {
duke@1: if (def == otherDef)
duke@1: return true;
duke@1:
duke@1: ClassDefinition superDef;
duke@1: if (def.getSuperClass() != null) {
duke@1: superDef = def.getSuperClass().getClassDefinition();
duke@1: if (inheritsFrom(superDef, otherDef))
duke@1: return true;
duke@1: }
duke@1:
duke@1: ClassDeclaration[] interfaces = def.getInterfaces();
duke@1: for (int i=0; i