/* * 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 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 {@code &&} 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"); } } } }