907 lines · 35.3 KB · Java
RawDownload
/* * Copyright (c) 1994, 2004, 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. */ package sun.tools.javac; import sun.tools.java.*;import sun.tools.tree.*;import sun.tools.asm.*;import java.util.Vector;import java.util.Enumeration;import java.util.Hashtable;import java.io.PrintStream; /** * A Source Member * * WARNING: The contents of this source file are not part of any * supported API.  Code that depends on them does so at its own risk: * they are subject to change or removal without notice. */@Deprecatedpublicclass SourceMember extends MemberDefinition implements Constants {    /**     * The argument names (if it is a method)     */    Vector args;     // set to the MemberDefinition in the interface if we have this field because    // it has been forced on us    MemberDefinition abstractSource;     /**     * The status of the field     */    int status;     static final int PARSED     = 0;    static final int CHECKING   = 1;    static final int CHECKED    = 2;    static final int INLINING   = 3;    static final int INLINED    = 4;    static final int ERROR      = 5;     public Vector getArguments() {        return args;    }     /**     * Constructor     * @param argNames a vector of IdentifierToken     */    public SourceMember(long where, ClassDefinition clazz,                       String doc, int modifiers, Type type,                       Identifier name, Vector argNames,                       IdentifierToken exp[], Node value) {        super(where, clazz, modifiers, type, name, exp, value);        this.documentation = doc;        this.args = argNames;   // for the moment        // not until type names are resolved: createArgumentFields(argNames);         if (ClassDefinition.containsDeprecated(documentation)) {            this.modifiers |= M_DEPRECATED;        }    }     void createArgumentFields(Vector argNames) {        // Create a list of arguments        if (isMethod()) {            args = new Vector();             if (isConstructor() || !(isStatic() || isInitializer())) {                args.addElement(((SourceClass)clazz).getThisArgument());            }             if (argNames != null) {                Enumeration e = argNames.elements();                Type argTypes[] = getType().getArgumentTypes();                for (int i = 0 ; i < argTypes.length ; i++) {                    Object x = e.nextElement();                    if (x instanceof LocalMember) {                        // This should not happen, but it does                        // in cases of vicious cyclic inheritance.                        args = argNames;                        return;                    }                    Identifier id;                    int mod;                    long where;                    if (x instanceof Identifier) {                        // allow argNames to be simple Identifiers (deprecated!)                        id = (Identifier)x;                        mod = 0;                        where = getWhere();                    } else {                        IdentifierToken token = (IdentifierToken)x;                        id = token.getName();                        mod = token.getModifiers();                        where = token.getWhere();                    }                    args.addElement(new LocalMember(where, clazz, mod,                                                   argTypes[i], id));                }            }        }    }     // The methods addOuterThis() and addUplevelArguments() were    // both originally part of a single method called addUplevelArguments()    // which took a single boolean parameter describing which of the    // two behaviors it wanted.    //    // The original addUplevelArguments() claimed to keep the arguments in    // the following order:    //    // (1) <this> <early outer this> <uplevel arguments...> <true arguments...>    //    // (By <early outer this> I am referring to the clientOuterField added    // to some constructors when they are created.  If an outer this is    // added later, on demand, then this is mixed in with the rest of the    // uplevel arguments and is added by addUplevelArguments.)    //    // In reality, the `args' Vector was generated in this order, but the    // Type array `argTypes' was generated as:    //    // (2) <this> <uplevel arguments...> <early outer this> <true arguments...>    //    // This didn't make a difference in the common case -- that is, when    // a class had an <outer.this> or <uplevel arguments...> but not both.    // Both can happen in the case that a member class is declared inside    // of a local class.  It seems that the calling sequences, generated    // in places like NewInstanceExpression.codeCommon(), use order (2),    // so I have changed the code below to stick with that order.  Since    // the only time this happens is in classes which are insideLocal, no    // one should be able to tell the difference between these orders.    // (bug number 4085633)     LocalMember outerThisArg = null;     /**     * Get outer instance link, or null if none.     */     public LocalMember getOuterThisArg() {        return outerThisArg;    }     /**     * Add the outer.this argument to the list of arguments for this     * constructor.  This is called from resolveTypeStructure.  Any     * additional uplevel arguments get added later by addUplevelArguments().     */     void addOuterThis() {        UplevelReference refs = clazz.getReferences();         // See if we have a client outer field.        while (refs != null &&               !refs.isClientOuterField()) {            refs = refs.getNext();        }         // There is no outer this argument.  Quit.        if (refs == null) {            return;        }         // Get the old arg types.        Type oldArgTypes[] = type.getArgumentTypes();         // And make an array for the new ones with space for one more.        Type argTypes[] = new Type[oldArgTypes.length + 1];         LocalMember arg = refs.getLocalArgument();        outerThisArg = arg;         // args is our list of arguments.  It contains a `this', so        // we insert at position 1.  The list of types does not have a        // this, so we insert at position 0.        args.insertElementAt(arg, 1);        argTypes[0] = arg.getType();         // Add on the rest of the constructor arguments.        for (int i = 0; i < oldArgTypes.length; i++) {            argTypes[i + 1] = oldArgTypes[i];        }         type = Type.tMethod(type.getReturnType(), argTypes);    }     /**     * Prepend argument names and argument types for local variable references.     * This information is never seen by the type-check phase,     * but it affects code generation, which is the earliest moment     * we have comprehensive information on uplevel references.     * The code() methods tweaks the constructor calls, prepending     * the proper values to the argument list.     */    void addUplevelArguments() {        UplevelReference refs = clazz.getReferences();        clazz.getReferencesFrozen();         // Count how many uplevels we have to add.        int count = 0;        for (UplevelReference r = refs; r != null; r = r.getNext()) {            if (!r.isClientOuterField()) {                count += 1;            }        }         if (count == 0) {            // None to add, quit.            return;        }         // Get the old argument types.        Type oldArgTypes[] = type.getArgumentTypes();         // Make an array with enough room for the new.        Type argTypes[] = new Type[oldArgTypes.length + count];         // Add all of the late uplevel references to args and argTypes.        // Note that they are `off-by-one' because of the `this'.        int ins = 0;        for (UplevelReference r = refs; r != null; r = r.getNext()) {            if (!r.isClientOuterField()) {                LocalMember arg = r.getLocalArgument();                 args.insertElementAt(arg, 1 + ins);                argTypes[ins] = arg.getType();                 ins++;            }        }         // Add the rest of the old arguments.        for (int i = 0; i < oldArgTypes.length; i++) {            argTypes[ins + i] = oldArgTypes[i];        }         type = Type.tMethod(type.getReturnType(), argTypes);    }     /**     * Constructor for an inner class.     */    public SourceMember(ClassDefinition innerClass) {        super(innerClass);    }     /**     * Constructor.     * Used only to generate an abstract copy of a method that a class     * inherits from an interface     */    public SourceMember(MemberDefinition f, ClassDefinition c, Environment env) {        this(f.getWhere(), c, f.getDocumentation(),             f.getModifiers() | M_ABSTRACT, f.getType(), f.getName(), null,             f.getExceptionIds(), null);        this.args = f.getArguments();        this.abstractSource = f;        this.exp = f.getExceptions(env);    }     /**     * Get exceptions     */    public ClassDeclaration[] getExceptions(Environment env) {        if ((!isMethod()) || (exp != null)) {            return exp;        }        if (expIds == null) {            // (should not happen)            exp = new ClassDeclaration[0];            return exp;        }        // be sure to get the imports right:        env = ((SourceClass)getClassDefinition()).setupEnv(env);        exp = new ClassDeclaration[expIds.length];        for (int i = 0; i < exp.length; i++) {            Identifier e = expIds[i].getName();            Identifier rexp = getClassDefinition().resolveName(env, e);            exp[i] = env.getClassDeclaration(rexp);        }        return exp;    }     /**     * Set array of name-resolved exceptions directly, e.g., for access methods.     */    public void setExceptions(ClassDeclaration[] exp) {        this.exp = exp;    }     /**     * Resolve types in a field, after parsing.     * @see ClassDefinition.resolveTypeStructure     */     public boolean resolved = false;     public void resolveTypeStructure(Environment env) {        if (tracing) env.dtEnter("SourceMember.resolveTypeStructure: " + this);         // A member should only be resolved once.  For a constructor, it is imperative        // that 'addOuterThis' be called only once, else the outer instance argument may        // be inserted into the argument list multiple times.         if (resolved) {            if (tracing) env.dtEvent("SourceMember.resolveTypeStructure: OK " + this);            // This case shouldn't be happening.  It is the responsibility            // of our callers to avoid attempting multiple resolutions of a member.            // *** REMOVE FOR SHIPMENT? ***            throw new CompilerError("multiple member type resolution");            //return;        } else {            if (tracing) env.dtEvent("SourceMember.resolveTypeStructure: RESOLVING " + this);            resolved = true;        }         super.resolveTypeStructure(env);        if (isInnerClass()) {            ClassDefinition nc = getInnerClass();            if (nc instanceof SourceClass && !nc.isLocal()) {                ((SourceClass)nc).resolveTypeStructure(env);            }            type = innerClass.getType();        } else {            // Expand all class names in 'type', including those that are not            // fully-qualified or refer to inner classes, into fully-qualified            // names.  Local and anonymous classes get synthesized names here,            // corresponding to the class files that will be generated.  This is            // currently the only place where 'resolveNames' is used.            type = env.resolveNames(getClassDefinition(), type, isSynthetic());             // do the throws also:            getExceptions(env);             if (isMethod()) {                Vector argNames = args; args = null;                createArgumentFields(argNames);                // Add outer instance argument for constructors.                if (isConstructor()) {                    addOuterThis();                }            }        }        if (tracing) env.dtExit("SourceMember.resolveTypeStructure: " + this);    }     /**     * Get the class declaration in which the field is actually defined     */    public ClassDeclaration getDefiningClassDeclaration() {        if (abstractSource == null)            return super.getDefiningClassDeclaration();        else            return abstractSource.getDefiningClassDeclaration();    }     /**     * A source field never reports deprecation, since the compiler     * allows access to deprecated features that are being compiled     * in the same job.     */    public boolean reportDeprecated(Environment env) {        return false;    }     /**     * Check this field.     * <p>     * This is the method which requests checking.     * The real work is done by     * <tt>Vset check(Environment, Context, Vset)</tt>.     */    public void check(Environment env) throws ClassNotFound {        if (tracing) env.dtEnter("SourceMember.check: " +                                 getName() + ", status = " + status);        // rely on the class to check all fields in the proper order        if (status == PARSED) {            if (isSynthetic() && getValue() == null) {                // break a big cycle for small synthetic variables                status = CHECKED;                if (tracing)                    env.dtExit("SourceMember.check: BREAKING CYCLE");                return;            }            if (tracing) env.dtEvent("SourceMember.check: CHECKING CLASS");            clazz.check(env);            if (status == PARSED) {                if (getClassDefinition().getError()) {                    status = ERROR;                } else {                    if (tracing)                        env.dtExit("SourceMember.check: CHECK FAILED");                    throw new CompilerError("check failed");                }            }        }        if (tracing) env.dtExit("SourceMember.check: DONE " +                                getName() + ", status = " + status);    }     /**     * Check a field.     * @param vset tells which uplevel variables are definitely assigned     * The vset is also used to track the initialization of blank finals     * by whichever fields which are relevant to them.     */    public Vset check(Environment env, Context ctx, Vset vset) throws ClassNotFound {        if (tracing) env.dtEvent("SourceMember.check: MEMBER " +                                 getName() + ", status = " + status);        if (status == PARSED) {            if (isInnerClass()) {                // some classes are checked separately                ClassDefinition nc = getInnerClass();                if (nc instanceof SourceClass && !nc.isLocal()                    && nc.isInsideLocal()) {                    status = CHECKING;                    vset = ((SourceClass)nc).checkInsideClass(env, ctx, vset);                }                status = CHECKED;                return vset;            }            if (env.dump()) {                System.out.println("[check field " + getClassDeclaration().getName() + "." + getName() + "]");                if (getValue() != null) {                    getValue().print(System.out);                    System.out.println();                }            }            env = new Environment(env, this);             // This is where all checking of names appearing within the type            // of the member is done.  Includes return type and argument types.            // Since only one location ('where') for error messages is provided,            // localization of errors is poor.  Throws clauses are handled below.            env.resolve(where, getClassDefinition(), getType());             // Make sure that all the classes that we claim to throw really            // are subclasses of Throwable, and are classes that we can reach            if (isMethod()) {                ClassDeclaration throwable =                    env.getClassDeclaration(idJavaLangThrowable);                ClassDeclaration exp[] = getExceptions(env);                for (int i = 0 ; i < exp.length ; i++) {                    ClassDefinition def;                    long where = getWhere();                    if (expIds != null && i < expIds.length) {                        where = IdentifierToken.getWhere(expIds[i], where);                    }                    try {                        def = exp[i].getClassDefinition(env);                         // Validate access for all inner-class components                        // of a qualified name, not just the last one, which                        // is checked below.  Yes, this is a dirty hack...                        // Part of fix for 4094658.                        env.resolveByName(where, getClassDefinition(), def.getName());                     } catch (ClassNotFound e) {                        env.error(where, "class.not.found", e.name, "throws");                        break;                    }                    def.noteUsedBy(getClassDefinition(), where, env);                    if (!getClassDefinition().                          canAccess(env, def.getClassDeclaration())) {                        env.error(where, "cant.access.class", def);                    } else if (!def.subClassOf(env, throwable)) {                        env.error(where, "throws.not.throwable", def);                    }                }            }             status = CHECKING;             if (isMethod() && args != null) {

Lines 1–500 of 907.