0001: /*
0002: * Copyright 1994-2004 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: package sun.tools.javac;
0027:
0028: import sun.tools.java.*;
0029: import sun.tools.tree.*;
0030: import sun.tools.tree.CompoundStatement;
0031: import sun.tools.asm.Assembler;
0032: import sun.tools.asm.ConstantPool;
0033: import java.util.Vector;
0034: import java.util.Enumeration;
0035: import java.util.Hashtable;
0036: import java.util.Iterator;
0037: import java.io.IOException;
0038: import java.io.OutputStream;
0039: import java.io.DataOutputStream;
0040: import java.io.ByteArrayOutputStream;
0041: import java.io.File;
0042:
0043: /**
0044: * This class represents an Java class as it is read from
0045: * an Java source file.
0046: *
0047: * WARNING: The contents of this source file are not part of any
0048: * supported API. Code that depends on them does so at its own risk:
0049: * they are subject to change or removal without notice.
0050: */
0051: @Deprecated
0052: public class SourceClass extends ClassDefinition {
0053:
0054: /**
0055: * The toplevel environment, shared with the parser
0056: */
0057: Environment toplevelEnv;
0058:
0059: /**
0060: * The default constructor
0061: */
0062: SourceMember defConstructor;
0063:
0064: /**
0065: * The constant pool
0066: */
0067: ConstantPool tab = new ConstantPool();
0068:
0069: /**
0070: * The list of class dependencies
0071: */
0072: Hashtable deps = new Hashtable(11);
0073:
0074: /**
0075: * The field used to represent "this" in all of my code.
0076: */
0077: LocalMember this Arg;
0078:
0079: /**
0080: * Last token of class, as reported by parser.
0081: */
0082: long endPosition;
0083:
0084: /**
0085: * Access methods for constructors are distinguished from
0086: * the constructors themselves by a dummy first argument.
0087: * A unique type used for this purpose and shared by all
0088: * constructor access methods within a package-member class is
0089: * maintained here.
0090: * <p>
0091: * This field is null except in an outermost class containing
0092: * one or more classes needing such an access method.
0093: */
0094: private Type dummyArgumentType = null;
0095:
0096: /**
0097: * Constructor
0098: */
0099: public SourceClass(Environment env, long where,
0100: ClassDeclaration declaration, String documentation,
0101: int modifiers, IdentifierToken super Class,
0102: IdentifierToken interfaces[], SourceClass outerClass,
0103: Identifier localName) {
0104: super (env.getSource(), where, declaration, modifiers,
0105: super Class, interfaces);
0106: setOuterClass(outerClass);
0107:
0108: this .toplevelEnv = env;
0109: this .documentation = documentation;
0110:
0111: if (ClassDefinition.containsDeprecated(documentation)) {
0112: this .modifiers |= M_DEPRECATED;
0113: }
0114:
0115: // Check for a package level class which is declared static.
0116: if (isStatic() && outerClass == null) {
0117: env.error(where, "static.class", this );
0118: this .modifiers &= ~M_STATIC;
0119: }
0120:
0121: // Inner classes cannot be static, nor can they be interfaces
0122: // (which are implicitly static). Static classes and interfaces
0123: // can only occur as top-level entities.
0124: //
0125: // Note that we do not have to check for local classes declared
0126: // to be static (this is currently caught by the parser) but
0127: // we check anyway in case the parser is modified to allow this.
0128: if (isLocal()
0129: || (outerClass != null && !outerClass.isTopLevel())) {
0130: if (isInterface()) {
0131: env.error(where, "inner.interface");
0132: } else if (isStatic()) {
0133: env.error(where, "static.inner.class", this );
0134: this .modifiers &= ~M_STATIC;
0135: if (innerClassMember != null) {
0136: innerClassMember.subModifiers(M_STATIC);
0137: }
0138: }
0139: }
0140:
0141: if (isPrivate() && outerClass == null) {
0142: env.error(where, "private.class", this );
0143: this .modifiers &= ~M_PRIVATE;
0144: }
0145: if (isProtected() && outerClass == null) {
0146: env.error(where, "protected.class", this );
0147: this .modifiers &= ~M_PROTECTED;
0148: }
0149: /*----*
0150: if ((isPublic() || isProtected()) && isInsideLocal()) {
0151: env.error(where, "warn.public.local.class", this);
0152: }
0153: *----*/
0154:
0155: // maybe define an uplevel "A.this" current instance field
0156: if (!isTopLevel() && !isLocal()) {
0157: LocalMember outerArg = ((SourceClass) outerClass)
0158: .getThisArgument();
0159: UplevelReference r = getReference(outerArg);
0160: setOuterMember(r.getLocalField(env));
0161: }
0162:
0163: // Set simple, unmangled local name for a local or anonymous class.
0164: // NOTE: It would be OK to do this unconditionally, as null is the
0165: // correct value for a member (non-local) class.
0166: if (localName != null)
0167: setLocalName(localName);
0168:
0169: // Check for inner class with same simple name as one of
0170: // its enclosing classes. Note that 'getLocalName' returns
0171: // the simple, unmangled source-level name of any class.
0172: // The previous version of this code was not careful to avoid
0173: // mangled local class names. This version fixes 4047746.
0174: Identifier this Name = getLocalName();
0175: if (this Name != idNull) {
0176: // Test above suppresses error for nested anonymous classes,
0177: // which have an internal "name", but are not named in source code.
0178: for (ClassDefinition scope = outerClass; scope != null; scope = scope
0179: .getOuterClass()) {
0180: Identifier outerName = scope.getLocalName();
0181: if (this Name.equals(outerName))
0182: env.error(where, "inner.redefined", this Name);
0183: }
0184: }
0185: }
0186:
0187: /**
0188: * Return last position in this class.
0189: * @see #getWhere
0190: */
0191: public long getEndPosition() {
0192: return endPosition;
0193: }
0194:
0195: public void setEndPosition(long endPosition) {
0196: this .endPosition = endPosition;
0197: }
0198:
0199: // JCOV
0200: /**
0201: * Return absolute name of source file
0202: */
0203: public String getAbsoluteName() {
0204: String AbsName = ((ClassFile) getSource()).getAbsoluteName();
0205:
0206: return AbsName;
0207: }
0208:
0209: //end JCOV
0210:
0211: /**
0212: * Return imports
0213: */
0214: public Imports getImports() {
0215: return toplevelEnv.getImports();
0216: }
0217:
0218: /**
0219: * Find or create my "this" argument, which is used for all methods.
0220: */
0221: public LocalMember getThisArgument() {
0222: if (this Arg == null) {
0223: this Arg = new LocalMember(where, this , 0, getType(), idThis);
0224: }
0225: return this Arg;
0226: }
0227:
0228: /**
0229: * Add a dependency
0230: */
0231: public void addDependency(ClassDeclaration c) {
0232: if (tab != null) {
0233: tab.put(c);
0234: }
0235: // If doing -xdepend option, save away list of class dependencies
0236: // making sure to NOT include duplicates or the class we are in
0237: // (Hashtable's put() makes sure we don't have duplicates)
0238: if (toplevelEnv.print_dependencies()
0239: && c != getClassDeclaration()) {
0240: deps.put(c, c);
0241: }
0242: }
0243:
0244: /**
0245: * Add a field (check it first)
0246: */
0247: public void addMember(Environment env, MemberDefinition f) {
0248: // Make sure the access permissions are self-consistent:
0249: switch (f.getModifiers() & (M_PUBLIC | M_PRIVATE | M_PROTECTED)) {
0250: case M_PUBLIC:
0251: case M_PRIVATE:
0252: case M_PROTECTED:
0253: case 0:
0254: break;
0255: default:
0256: env.error(f.getWhere(), "inconsistent.modifier", f);
0257: // Cut out the more restrictive modifier(s):
0258: if (f.isPublic()) {
0259: f.subModifiers(M_PRIVATE | M_PROTECTED);
0260: } else {
0261: f.subModifiers(M_PRIVATE);
0262: }
0263: break;
0264: }
0265:
0266: // Note exemption for synthetic members below.
0267: if (f.isStatic() && !isTopLevel() && !f.isSynthetic()) {
0268: if (f.isMethod()) {
0269: env.error(f.getWhere(), "static.inner.method", f, this );
0270: f.subModifiers(M_STATIC);
0271: } else if (f.isVariable()) {
0272: if (!f.isFinal() || f.isBlankFinal()) {
0273: env.error(f.getWhere(), "static.inner.field", f
0274: .getName(), this );
0275: f.subModifiers(M_STATIC);
0276: }
0277: // Even if a static passes this test, there is still another
0278: // check in 'SourceMember.check'. The check is delayed so
0279: // that the initializer may be inspected more closely, using
0280: // 'isConstant()'. Part of fix for 4095568.
0281: } else {
0282: // Static inner classes are diagnosed in 'SourceClass.<init>'.
0283: f.subModifiers(M_STATIC);
0284: }
0285: }
0286:
0287: if (f.isMethod()) {
0288: if (f.isConstructor()) {
0289: if (f.getClassDefinition().isInterface()) {
0290: env.error(f.getWhere(), "intf.constructor");
0291: return;
0292: }
0293: if (f.isNative() || f.isAbstract() || f.isStatic()
0294: || f.isSynchronized() || f.isFinal()) {
0295: env.error(f.getWhere(), "constr.modifier", f);
0296: f.subModifiers(M_NATIVE | M_ABSTRACT | M_STATIC
0297: | M_SYNCHRONIZED | M_FINAL);
0298: }
0299: } else if (f.isInitializer()) {
0300: if (f.getClassDefinition().isInterface()) {
0301: env.error(f.getWhere(), "intf.initializer");
0302: return;
0303: }
0304: }
0305:
0306: // f is not allowed to return an array of void
0307: if ((f.getType().getReturnType()).isVoidArray()) {
0308: env.error(f.getWhere(), "void.array");
0309: }
0310:
0311: if (f.getClassDefinition().isInterface()
0312: && (f.isStatic() || f.isSynchronized()
0313: || f.isNative() || f.isFinal()
0314: || f.isPrivate() || f.isProtected())) {
0315: env.error(f.getWhere(), "intf.modifier.method", f);
0316: f.subModifiers(M_STATIC | M_SYNCHRONIZED | M_NATIVE
0317: | M_FINAL | M_PRIVATE);
0318: }
0319: if (f.isTransient()) {
0320: env.error(f.getWhere(), "transient.meth", f);
0321: f.subModifiers(M_TRANSIENT);
0322: }
0323: if (f.isVolatile()) {
0324: env.error(f.getWhere(), "volatile.meth", f);
0325: f.subModifiers(M_VOLATILE);
0326: }
0327: if (f.isAbstract()) {
0328: if (f.isPrivate()) {
0329: env.error(f.getWhere(),
0330: "abstract.private.modifier", f);
0331: f.subModifiers(M_PRIVATE);
0332: }
0333: if (f.isStatic()) {
0334: env.error(f.getWhere(), "abstract.static.modifier",
0335: f);
0336: f.subModifiers(M_STATIC);
0337: }
0338: if (f.isFinal()) {
0339: env.error(f.getWhere(), "abstract.final.modifier",
0340: f);
0341: f.subModifiers(M_FINAL);
0342: }
0343: if (f.isNative()) {
0344: env.error(f.getWhere(), "abstract.native.modifier",
0345: f);
0346: f.subModifiers(M_NATIVE);
0347: }
0348: if (f.isSynchronized()) {
0349: env.error(f.getWhere(),
0350: "abstract.synchronized.modifier", f);
0351: f.subModifiers(M_SYNCHRONIZED);
0352: }
0353: }
0354: if (f.isAbstract() || f.isNative()) {
0355: if (f.getValue() != null) {
0356: env.error(f.getWhere(), "invalid.meth.body", f);
0357: f.setValue(null);
0358: }
0359: } else {
0360: if (f.getValue() == null) {
0361: if (f.isConstructor()) {
0362: env.error(f.getWhere(), "no.constructor.body",
0363: f);
0364: } else {
0365: env.error(f.getWhere(), "no.meth.body", f);
0366: }
0367: f.addModifiers(M_ABSTRACT);
0368: }
0369: }
0370: Vector arguments = f.getArguments();
0371: if (arguments != null) {
0372: // arguments can be null if this is an implicit abstract method
0373: int argumentLength = arguments.size();
0374: Type argTypes[] = f.getType().getArgumentTypes();
0375: for (int i = 0; i < argTypes.length; i++) {
0376: Object arg = arguments.elementAt(i);
0377: long where = f.getWhere();
0378: if (arg instanceof MemberDefinition) {
0379: where = ((MemberDefinition) arg).getWhere();
0380: arg = ((MemberDefinition) arg).getName();
0381: }
0382: // (arg should be an Identifier now)
0383: if (argTypes[i].isType(TC_VOID)
0384: || argTypes[i].isVoidArray()) {
0385: env.error(where, "void.argument", arg);
0386: }
0387: }
0388: }
0389: } else if (f.isInnerClass()) {
0390: if (f.isVolatile() || f.isTransient() || f.isNative()
0391: || f.isSynchronized()) {
0392: env.error(f.getWhere(), "inner.modifier", f);
0393: f.subModifiers(M_VOLATILE | M_TRANSIENT | M_NATIVE
0394: | M_SYNCHRONIZED);
0395: }
0396: // same check as for fields, below:
0397: if (f.getClassDefinition().isInterface()
0398: && (f.isPrivate() || f.isProtected())) {
0399: env.error(f.getWhere(), "intf.modifier.field", f);
0400: f.subModifiers(M_PRIVATE | M_PROTECTED);
0401: f.addModifiers(M_PUBLIC);
0402: // Fix up the class itself to agree with
0403: // the inner-class member.
0404: ClassDefinition c = f.getInnerClass();
0405: c.subModifiers(M_PRIVATE | M_PROTECTED);
0406: c.addModifiers(M_PUBLIC);
0407: }
0408: } else {
0409: if (f.getType().isType(TC_VOID)
0410: || f.getType().isVoidArray()) {
0411: env.error(f.getWhere(), "void.inst.var", f.getName());
0412: // REMIND: set type to error
0413: return;
0414: }
0415:
0416: if (f.isSynchronized() || f.isAbstract() || f.isNative()) {
0417: env.error(f.getWhere(), "var.modifier", f);
0418: f.subModifiers(M_SYNCHRONIZED | M_ABSTRACT | M_NATIVE);
0419: }
0420: if (f.isStrict()) {
0421: env.error(f.getWhere(), "var.floatmodifier", f);
0422: f.subModifiers(M_STRICTFP);
0423: }
0424: if (f.isTransient() && isInterface()) {
0425: env.error(f.getWhere(), "transient.modifier", f);
0426: f.subModifiers(M_TRANSIENT);
0427: }
0428: if (f.isVolatile() && (isInterface() || f.isFinal())) {
0429: env.error(f.getWhere(), "volatile.modifier", f);
0430: f.subModifiers(M_VOLATILE);
0431: }
0432: if (f.isFinal() && (f.getValue() == null) && isInterface()) {
0433: env.error(f.getWhere(), "initializer.needed", f);
0434: f.subModifiers(M_FINAL);
0435: }
0436:
0437: if (f.getClassDefinition().isInterface()
0438: && (f.isPrivate() || f.isProtected())) {
0439: env.error(f.getWhere(), "intf.modifier.field", f);
0440: f.subModifiers(M_PRIVATE | M_PROTECTED);
0441: f.addModifiers(M_PUBLIC);
0442: }
0443: }
0444: // Do not check for repeated methods here: Types are not yet resolved.
0445: if (!f.isInitializer()) {
0446: for (MemberDefinition f2 = getFirstMatch(f.getName()); f2 != null; f2 = f2
0447: .getNextMatch()) {
0448: if (f.isVariable() && f2.isVariable()) {
0449: env.error(f.getWhere(), "var.multidef", f, f2);
0450: return;
0451: } else if (f.isInnerClass() && f2.isInnerClass()
0452: && !f.getInnerClass().isLocal()
0453: && !f2.getInnerClass().isLocal()) {
0454: // Found a duplicate inner-class member.
0455: // Duplicate local classes are detected in
0456: // 'VarDeclarationStatement.checkDeclaration'.
0457: env.error(f.getWhere(), "inner.class.multidef", f);
0458: return;
0459: }
0460: }
0461: }
0462:
0463: super .addMember(env, f);
0464: }
0465:
0466: /**
0467: * Create an environment suitable for checking this class.
0468: * Make sure the source and imports are set right.
0469: * Make sure the environment contains no context information.
0470: * (Actually, throw away env altogether and use toplevelEnv instead.)
0471: */
0472: public Environment setupEnv(Environment env) {
0473: // In some cases, we go to some trouble to create the 'env' argument
0474: // that is discarded. We should remove the 'env' argument entirely
0475: // as well as the vestigial code that supports it. See comments on
0476: // 'newEnvironment' in 'checkInternal' below.
0477: return new Environment(toplevelEnv, this );
0478: }
0479:
0480: /**
0481: * A source class never reports deprecation, since the compiler
0482: * allows access to deprecated features that are being compiled
0483: * in the same job.
0484: */
0485: public boolean reportDeprecated(Environment env) {
0486: return false;
0487: }
0488:
0489: /**
0490: * See if the source file of this class is right.
0491: * @see ClassDefinition#noteUsedBy
0492: */
0493: public void noteUsedBy(ClassDefinition ref, long where,
0494: Environment env) {
0495: // If this class is not public, watch for cross-file references.
0496: super .noteUsedBy(ref, where, env);
0497: ClassDefinition def = this ;
0498: while (def.isInnerClass()) {
0499: def = def.getOuterClass();
0500: }
0501: if (def.isPublic()) {
0502: return; // already checked
0503: }
0504: while (ref.isInnerClass()) {
0505: ref = ref.getOuterClass();
0506: }
0507: if (def.getSource().equals(ref.getSource())) {
0508: return; // intra-file reference
0509: }
0510: ((SourceClass) def).checkSourceFile(env, where);
0511: }
0512:
0513: /**
0514: * Check this class and all its fields.
0515: */
0516: public void check(Environment env) throws ClassNotFound {
0517: if (tracing)
0518: env.dtEnter("SourceClass.check: " + getName());
0519: if (isInsideLocal()) {
0520: // An inaccessible class gets checked when the surrounding
0521: // block is checked.
0522: // QUERY: Should this case ever occur?
0523: // What would invoke checking of a local class aside from
0524: // checking the surrounding method body?
0525: if (tracing)
0526: env.dtEvent("SourceClass.check: INSIDE LOCAL "
0527: + getOuterClass().getName());
0528: getOuterClass().check(env);
0529: } else {
0530: if (isInnerClass()) {
0531: if (tracing)
0532: env.dtEvent("SourceClass.check: INNER CLASS "
0533: + getOuterClass().getName());
0534: // Make sure the outer is checked first.
0535: ((SourceClass) getOuterClass()).maybeCheck(env);
0536: }
0537: Vset vset = new Vset();
0538: Context ctx = null;
0539: if (tracing)
0540: env.dtEvent("SourceClass.check: CHECK INTERNAL "
0541: + getName());
0542: vset = checkInternal(setupEnv(env), ctx, vset);
0543: // drop vset here
0544: }
0545: if (tracing)
0546: env.dtExit("SourceClass.check: " + getName());
0547: }
0548:
0549: private void maybeCheck(Environment env) throws ClassNotFound {
0550: if (tracing)
0551: env.dtEvent("SourceClass.maybeCheck: " + getName());
0552: // Check this class now, if it has not yet been checked.
0553: // Cf. Main.compile(). Perhaps this code belongs there somehow.
0554: ClassDeclaration c = getClassDeclaration();
0555: if (c.getStatus() == CS_PARSED) {
0556: // Set it first to avoid vicious circularity:
0557: c.setDefinition(this , CS_CHECKED);
0558: check(env);
0559: }
0560: }
0561:
0562: private Vset checkInternal(Environment env, Context ctx, Vset vset)
0563: throws ClassNotFound {
0564: Identifier nm = getClassDeclaration().getName();
0565: if (env.verbose()) {
0566: env.output("[checking class " + nm + "]");
0567: }
0568:
0569: // Save context enclosing class for later access
0570: // by 'ClassDefinition.resolveName.'
0571: classContext = ctx;
0572:
0573: // At present, the call to 'newEnvironment' is not needed.
0574: // The incoming environment to 'basicCheck' is always passed to
0575: // 'setupEnv', which discards it completely. This is also the
0576: // only call to 'newEnvironment', which is now apparently dead code.
0577: basicCheck(Context.newEnvironment(env, ctx));
0578:
0579: // Validate access for all inner-class components
0580: // of a qualified name, not just the last one, which
0581: // is checked below. Yes, this is a dirty hack...
0582: // Much of this code was cribbed from 'checkSupers'.
0583: // Part of fix for 4094658.
0584: ClassDeclaration sup = getSuperClass();
0585: if (sup != null) {
0586: long where = getWhere();
0587: where = IdentifierToken.getWhere(super ClassId, where);
0588: env.resolveExtendsByName(where, this , sup.getName());
0589: }
0590: for (int i = 0; i < interfaces.length; i++) {
0591: ClassDeclaration intf = interfaces[i];
0592: long where = getWhere();
0593: // Error localization fails here if interfaces were
0594: // elided during error recovery from an invalid one.
0595: if (interfaceIds != null
0596: && interfaceIds.length == interfaces.length) {
0597: where = IdentifierToken
0598: .getWhere(interfaceIds[i], where);
0599: }
0600: env.resolveExtendsByName(where, this , intf.getName());
0601: }
0602:
0603: // Does the name already exist in an imported package?
0604: // See JLS 8.1 for the precise rules.
0605: if (!isInnerClass() && !isInsideLocal()) {
0606: // Discard package qualification for the import checks.
0607: Identifier simpleName = nm.getName();
0608: try {
0609: // We want this to throw a ClassNotFound exception
0610: Imports imports = toplevelEnv.getImports();
0611: Identifier ID = imports.resolve(env, simpleName);
0612: if (ID != getName())
0613: env.error(where, "class.multidef.import",
0614: simpleName, ID);
0615: } catch (AmbiguousClass e) {
0616: // At least one of e.name1 and e.name2 must be different
0617: Identifier ID = (e.name1 != getName()) ? e.name1
0618: : e.name2;
0619: env.error(where, "class.multidef.import", simpleName,
0620: ID);
0621: } catch (ClassNotFound e) {
0622: // we want this to happen
0623: }
0624:
0625: // Make sure that no package with the same fully qualified
0626: // name exists. This is required by JLS 7.1. We only need
0627: // to perform this check for top level classes -- it isn't
0628: // necessary for inner classes. (bug 4101529)
0629: //
0630: // This change has been backed out because, on WIN32, it
0631: // failed to distinguish between java.awt.event and
0632: // java.awt.Event when looking for a directory. We will
0633: // add this back in later.
0634: //
0635: // try {
0636: // if (env.getPackage(nm).exists()) {
0637: // env.error(where, "class.package.conflict", nm);
0638: // }
0639: // } catch (java.io.IOException ee) {
0640: // env.error(where, "io.exception.package", nm);
0641: // }
0642:
0643: // Make sure it was defined in the right file
0644: if (isPublic()) {
0645: checkSourceFile(env, getWhere());
0646: }
0647: }
0648:
0649: vset = checkMembers(env, ctx, vset);
0650: return vset;
0651: }
0652:
0653: private boolean sourceFileChecked = false;
0654:
0655: /**
0656: * See if the source file of this class is of the right name.
0657: */
0658: public void checkSourceFile(Environment env, long where) {
0659: // one error per offending class is sufficient
0660: if (sourceFileChecked)
0661: return;
0662: sourceFileChecked = true;
0663:
0664: String fname = getName().getName() + ".java";
0665: String src = ((ClassFile) getSource()).getName();
0666: if (!src.equals(fname)) {
0667: if (isPublic()) {
0668: env.error(where, "public.class.file", this , fname);
0669: } else {
0670: env.error(where, "warn.package.class.file", this , src,
0671: fname);
0672: }
0673: }
0674: }
0675:
0676: // Set true if superclass (but not necessarily superinterfaces) have
0677: // been checked. If the superclass is still unresolved, then an error
0678: // message should have been issued, and we assume that no further
0679: // resolution is possible.
0680: private boolean super sChecked = false;
0681:
0682: /**
0683: * Overrides 'ClassDefinition.getSuperClass'.
0684: */
0685:
0686: public ClassDeclaration getSuperClass(Environment env) {
0687: if (tracing)
0688: env.dtEnter("SourceClass.getSuperClass: " + this );
0689: // Superclass may fail to be set because of error recovery,
0690: // so resolve types here only if 'checkSupers' has not yet
0691: // completed its checks on the superclass.
0692: // QUERY: Can we eliminate the need to resolve superclasses on demand?
0693: // See comments in 'checkSupers' and in 'ClassDefinition.getInnerClass'.
0694: if (super Class == null && super ClassId != null
0695: && !super sChecked) {
0696: resolveTypeStructure(env);
0697: // We used to report an error here if the superclass was not
0698: // resolved. Having moved the call to 'checkSupers' from 'basicCheck'
0699: // into 'resolveTypeStructure', the errors reported here should have
0700: // already been reported. Furthermore, error recovery can null out
0701: // the superclass, which would cause a spurious error from the test here.
0702: }
0703: if (tracing)
0704: env.dtExit("SourceClass.getSuperClass: " + this );
0705: return super Class;
0706: }
0707:
0708: /**
0709: * Check that all superclasses and superinterfaces are defined and
0710: * well formed. Among other checks, verify that the inheritance
0711: * graph is acyclic. Called from 'resolveTypeStructure'.
0712: */
0713:
0714: private void checkSupers(Environment env) throws ClassNotFound {
0715:
0716: // *** DEBUG ***
0717: super sCheckStarted = true;
0718:
0719: if (tracing)
0720: env.dtEnter("SourceClass.checkSupers: " + this );
0721:
0722: if (isInterface()) {
0723: if (isFinal()) {
0724: Identifier nm = getClassDeclaration().getName();
0725: env.error(getWhere(), "final.intf", nm);
0726: // Interfaces have no superclass. Superinterfaces
0727: // are checked below, in code shared with the class case.
0728: }
0729: } else {
0730: // Check superclass.
0731: // Call to 'getSuperClass(env)' (note argument) attempts
0732: // 'resolveTypeStructure' if superclass has not successfully
0733: // been resolved. Since we have just now called 'resolveSupers'
0734: // (see our call in 'resolveTypeStructure'), it is not clear
0735: // that this can do any good. Why not 'getSuperClass()' here?
0736: if (getSuperClass(env) != null) {
0737: long where = getWhere();
0738: where = IdentifierToken.getWhere(super ClassId, where);
0739: try {
0740: ClassDefinition def = getSuperClass()
0741: .getClassDefinition(env);
0742: // Resolve superclass and its ancestors.
0743: def.resolveTypeStructure(env);
0744: // Access to the superclass should be checked relative
0745: // to the surrounding context, not as if the reference
0746: // appeared within the class body. Changed 'canAccess'
0747: // to 'extendsCanAccess' to fix 4087314.
0748: if (!extendsCanAccess(env, getSuperClass())) {
0749: env.error(where, "cant.access.class",
0750: getSuperClass());
0751: // Might it be a better recovery to let the access go through?
0752: super Class = null;
0753: } else if (def.isFinal()) {
0754: env.error(where, "super.is.final",
0755: getSuperClass());
0756: // Might it be a better recovery to let the access go through?
0757: super Class = null;
0758: } else if (def.isInterface()) {
0759: env.error(where, "super.is.intf",
0760: getSuperClass());
0761: super Class = null;
0762: } else if (super ClassOf(env, getSuperClass())) {
0763: env.error(where, "cyclic.super");
0764: super Class = null;
0765: } else {
0766: def.noteUsedBy(this , where, env);
0767: }
0768: if (super Class == null) {
0769: def = null;
0770: } else {
0771: // If we have a valid superclass, check its
0772: // supers as well, and so on up to root class.
0773: // Call to 'enclosingClassOf' will raise
0774: // 'NullPointerException' if 'def' is null,
0775: // so omit this check as error recovery.
0776: ClassDefinition sup = def;
0777: for (;;) {
0778: if (enclosingClassOf(sup)) {
0779: // Do we need a similar test for
0780: // interfaces? See bugid 4038529.
0781: env.error(where, "super.is.inner");
0782: super Class = null;
0783: break;
0784: }
0785: // Since we resolved the superclass and its
0786: // ancestors above, we should not discover
0787: // any unresolved classes on the superclass
0788: // chain. It should thus be sufficient to
0789: // call 'getSuperClass()' (no argument) here.
0790: ClassDeclaration s = sup.getSuperClass(env);
0791: if (s == null) {
0792: // Superclass not resolved due to error.
0793: break;
0794: }
0795: sup = s.getClassDefinition(env);
0796: }
0797: }
0798: } catch (ClassNotFound e) {
0799: // Error is detected in call to 'getClassDefinition'.
0800: // The class may actually exist but be ambiguous.
0801: // Call env.resolve(e.name) to see if it is.
0802: // env.resolve(name) will definitely tell us if the
0803: // class is ambiguous, but may not necessarily tell
0804: // us if the class is not found.
0805: // (part of solution for 4059855)
0806: reportError: {
0807: try {
0808: env.resolve(e.name);
0809: } catch (AmbiguousClass ee) {
0810: env.error(where, "ambig.class", ee.name1,
0811: ee.name2);
0812: super Class = null;
0813: break reportError;
0814: } catch (ClassNotFound ee) {
0815: // fall through
0816: }
0817: env.error(where, "super.not.found", e.name,
0818: this );
0819: super Class = null;
0820: } // The break exits this block
0821: }
0822:
0823: } else {
0824: // Superclass was null on entry, after call to
0825: // 'resolveSupers'. This should normally not happen,
0826: // as 'resolveSupers' sets 'superClass' to a non-null
0827: // value for all named classes, except for one special
0828: // case: 'java.lang.Object', which has no superclass.
0829: if (isAnonymous()) {
0830: // checker should have filled it in first
0831: throw new CompilerError("anonymous super");
0832: } else if (!getName().equals(idJavaLangObject)) {
0833: throw new CompilerError("unresolved super");
0834: }
0835: }
0836: }
0837:
0838: // At this point, if 'superClass' is null due to an error
0839: // in the user program, a message should have been issued.
0840: super sChecked = true;
0841:
0842: // Check interfaces
0843: for (int i = 0; i < interfaces.length; i++) {
0844: ClassDeclaration intf = interfaces[i];
0845: long where = getWhere();
0846: if (interfaceIds != null
0847: && interfaceIds.length == interfaces.length) {
0848: where = IdentifierToken
0849: .getWhere(interfaceIds[i], where);
0850: }
0851: try {
0852: ClassDefinition def = intf.getClassDefinition(env);
0853: // Resolve superinterface and its ancestors.
0854: def.resolveTypeStructure(env);
0855: // Check superinterface access in the correct context.
0856: // Changed 'canAccess' to 'extendsCanAccess' to fix 4087314.
0857: if (!extendsCanAccess(env, intf)) {
0858: env.error(where, "cant.access.class", intf);
0859: } else if (!intf.getClassDefinition(env).isInterface()) {
0860: env.error(where, "not.intf", intf);
0861: } else if (isInterface() && implementedBy(env, intf)) {
0862: env.error(where, "cyclic.intf", intf);
0863: } else {
0864: def.noteUsedBy(this , where, env);
0865: // Interface is OK, leave it in the interface list.
0866: continue;
0867: }
0868: } catch (ClassNotFound e) {
0869: // The interface may actually exist but be ambiguous.
0870: // Call env.resolve(e.name) to see if it is.
0871: // env.resolve(name) will definitely tell us if the
0872: // interface is ambiguous, but may not necessarily tell
0873: // us if the interface is not found.
0874: // (part of solution for 4059855)
0875: reportError2: {
0876: try {
0877: env.resolve(e.name);
0878: } catch (AmbiguousClass ee) {
0879: env.error(where, "ambig.class", ee.name1,
0880: ee.name2);
0881: super Class = null;
0882: break reportError2;
0883: } catch (ClassNotFound ee) {
0884: // fall through
0885: }
0886: env.error(where, "intf.not.found", e.name, this );
0887: super Class = null;
0888: } // The break exits this block
0889: }
0890: // Remove this interface from the list of interfaces
0891: // as recovery from an error.
0892: ClassDeclaration newInterfaces[] = new ClassDeclaration[interfaces.length - 1];
0893: System.arraycopy(interfaces, 0, newInterfaces, 0, i);
0894: System.arraycopy(interfaces, i + 1, newInterfaces, i,
0895: newInterfaces.length - i);
0896: interfaces = newInterfaces;
0897: --i;
0898: }
0899: if (tracing)
0900: env.dtExit("SourceClass.checkSupers: " + this );
0901: }
0902:
0903: /**
0904: * Check all of the members of this class.
0905: * <p>
0906: * Inner classes are checked in the following way. Any class which
0907: * is immediately contained in a block (anonymous and local classes)
0908: * is checked along with its containing method; see the
0909: * SourceMember.check() method for more information. Member classes
0910: * of this class are checked immediately after this class, unless this
0911: * class is insideLocal(), in which case, they are checked with the
0912: * rest of the members.
0913: */
0914: private Vset checkMembers(Environment env, Context ctx, Vset vset)
0915: throws ClassNotFound {
0916:
0917: // bail out if there were any errors
0918: if (getError()) {
0919: return vset;
0920: }
0921:
0922: // Make sure that all of our member classes have been
0923: // basicCheck'ed before we check the rest of our members.
0924: // If our member classes haven't been basicCheck'ed, then they
0925: // may not have <init> methods. It is important that they
0926: // have <init> methods so we can process NewInstanceExpressions
0927: // correctly. This problem didn't occur before 1.2beta1.
0928: // This is a fix for bug 4082816.
0929: for (MemberDefinition f = getFirstMember(); f != null; f = f
0930: .getNextMember()) {
0931: if (f.isInnerClass()) {
0932: // System.out.println("Considering " + f + " in " + this);
0933: SourceClass cdef = (SourceClass) f.getInnerClass();
0934: if (cdef.isMember()) {
0935: cdef.basicCheck(env);
0936: }
0937: }
0938: }
0939:
0940: if (isFinal() && isAbstract()) {
0941: env
0942: .error(where, "final.abstract", this .getName()
0943: .getName());
0944: }
0945:
0946: // This class should be abstract if there are any abstract methods
0947: // in our parent classes and interfaces which we do not override.
0948: // There are odd cases when, even though we cannot access some
0949: // abstract method from our superclass, that abstract method can
0950: // still force this class to be abstract. See the discussion in
0951: // bug id 1240831.
0952: if (!isInterface() && !isAbstract() && mustBeAbstract(env)) {
0953: // Set the class abstract.
0954: modifiers |= M_ABSTRACT;
0955:
0956: // Tell the user which methods force this class to be abstract.
0957:
0958: // First list all of the "unimplementable" abstract methods.
0959: Iterator iter = getPermanentlyAbstractMethods();
0960: while (iter.hasNext()) {
0961: MemberDefinition method = (MemberDefinition) iter
0962: .next();
0963: // We couldn't override this method even if we
0964: // wanted to. Try to make the error message
0965: // as non-confusing as possible.
0966: env.error(where, "abstract.class.cannot.override",
0967: getClassDeclaration(), method, method
0968: .getDefiningClassDeclaration());
0969: }
0970:
0971: // Now list all of the traditional abstract methods.
0972: iter = getMethods(env);
0973: while (iter.hasNext()) {
0974: // For each method, check if it is abstract. If it is,
0975: // output an appropriate error message.
0976: MemberDefinition method = (MemberDefinition) iter
0977: .next();
0978: if (method.isAbstract()) {
0979: env.error(where, "abstract.class",
0980: getClassDeclaration(), method, method
0981: .getDefiningClassDeclaration());
0982: }
0983: }
0984: }
0985:
0986: // Check the instance variables in a pre-pass before any constructors.
0987: // This lets constructors "in-line" any initializers directly.
0988: // It also lets us do some definite assignment checks on variables.
0989: Context ctxInit = new Context(ctx);
0990: Vset vsInst = vset.copy();
0991: Vset vsClass = vset.copy();
0992:
0993: // Do definite assignment checking on blank finals.
0994: // Other variables do not need such checks. The simple textual
0995: // ordering constraints implemented by MemberDefinition.canReach()
0996: // are necessary and sufficient for the other variables.
0997: // Note that within non-static code, all statics are always
0998: // definitely assigned, and vice-versa.
0999: for (MemberDefinition f = getFirstMember(); f != null; f = f
1000: .getNextMember()) {
1001: if (f.isVariable() && f.isBlankFinal()) {
1002: // The following allocates a LocalMember object as a proxy
1003: // to represent the field.
1004: int number = ctxInit.declareFieldNumber(f);
1005: if (f.isStatic()) {
1006: vsClass = vsClass.addVarUnassigned(number);
1007: vsInst = vsInst.addVar(number);
1008: } else {
1009: vsInst = vsInst.addVarUnassigned(number);
1010: vsClass = vsClass.addVar(number);
1011: }
1012: }
1013: }
1014:
1015: // For instance variable checks, use a context with a "this" parameter.
1016: Context ctxInst = new Context(ctxInit, this );
1017: LocalMember this Arg = getThisArgument();
1018: int this Number = ctxInst.declare(env, this Arg);
1019: vsInst = vsInst.addVar(this Number);
1020:
1021: // Do all the initializers in order, checking the definite
1022: // assignment of blank finals. Separate static from non-static.
1023: for (MemberDefinition f = getFirstMember(); f != null; f = f
1024: .getNextMember()) {
1025: try {
1026: if (f.isVariable() || f.isInitializer()) {
1027: if (f.isStatic()) {
1028: vsClass = f.check(env, ctxInit, vsClass);
1029: } else {
1030: vsInst = f.check(env, ctxInst, vsInst);
1031: }
1032: }
1033: } catch (ClassNotFound ee) {
1034: env.error(f.getWhere(), "class.not.found", ee.name,
1035: this );
1036: }
1037: }
1038:
1039: checkBlankFinals(env, ctxInit, vsClass, true);
1040:
1041: // Check the rest of the field definitions.
1042: // (Note: Re-checking a field is a no-op.)
1043: for (MemberDefinition f = getFirstMember(); f != null; f = f
1044: .getNextMember()) {
1045: try {
1046: if (f.isConstructor()) {
1047: // When checking a constructor, an explicit call to
1048: // 'this(...)' makes all blank finals definitely assigned.
1049: // See 'MethodExpression.checkValue'.
1050: Vset vsCon = f.check(env, ctxInit, vsInst.copy());
1051: // May issue multiple messages for the same variable!!
1052: checkBlankFinals(env, ctxInit, vsCon, false);
1053: // (drop vsCon here)
1054: } else {
1055: Vset vsFld = f.check(env, ctx, vset.copy());
1056: // (drop vsFld here)
1057: }
1058: } catch (ClassNotFound ee) {
1059: env.error(f.getWhere(), "class.not.found", ee.name,
1060: this );
1061: }
1062: }
1063:
1064: // Must mark class as checked before visiting inner classes,
1065: // as they may in turn request checking of the current class
1066: // as an outer class. Fix for bug id 4056774.
1067: getClassDeclaration().setDefinition(this , CS_CHECKED);
1068:
1069: // Also check other classes in the same nest.
1070: // All checking of this nest must be finished before any
1071: // of its classes emit bytecode.
1072: // Otherwise, the inner classes might not have a chance to
1073: // add access or class literal fields to the outer class.
1074: for (MemberDefinition f = getFirstMember(); f != null; f = f
1075: .getNextMember()) {
1076: if (f.isInnerClass()) {
1077: SourceClass cdef = (SourceClass) f.getInnerClass();
1078: if (!cdef.isInsideLocal()) {
1079: cdef.maybeCheck(env);
1080: }
1081: }
1082: }
1083:
1084: // Note: Since inner classes cannot set up-level variables,
1085: // the returned vset is always equal to the passed-in vset.
1086: // Still, we'll return it for the sake of regularity.
1087: return vset;
1088: }
1089:
1090: /** Make sure all my blank finals exist now. */
1091:
1092: private void checkBlankFinals(Environment env, Context ctxInit,
1093: Vset vset, boolean isStatic) {
1094: for (int i = 0; i < ctxInit.getVarNumber(); i++) {
1095: if (!vset.testVar(i)) {
1096: MemberDefinition ff = ctxInit.getElement(i);
1097: if (ff != null && ff.isBlankFinal()
1098: && ff.isStatic() == isStatic
1099: && ff.getClassDefinition() == this ) {
1100: env.error(ff.getWhere(),
1101: "final.var.not.initialized", ff.getName());
1102: }
1103: }
1104: }
1105: }
1106:
1107: /**
1108: * Check this class has its superclass and its interfaces. Also
1109: * force it to have an <init> method (if it doesn't already have one)
1110: * and to have all the abstract methods of its parents.
1111: */
1112: private boolean basicChecking = false;
1113: private boolean basicCheckDone = false;
1114:
1115: protected void basicCheck(Environment env) throws ClassNotFound {
1116:
1117: if (tracing)
1118: env.dtEnter("SourceClass.basicCheck: " + getName());
1119:
1120: super .basicCheck(env);
1121:
1122: if (basicChecking || basicCheckDone) {
1123: if (tracing)
1124: env.dtExit("SourceClass.basicCheck: OK " + getName());
1125: return;
1126: }
1127:
1128: if (tracing)
1129: env
1130: .dtEvent("SourceClass.basicCheck: CHECKING "
1131: + getName());
1132:
1133: basicChecking = true;
1134:
1135: env = setupEnv(env);
1136:
1137: Imports imports = env.getImports();
1138: if (imports != null) {
1139: imports.resolve(env);
1140: }
1141:
1142: resolveTypeStructure(env);
1143:
1144: // Check the existence of the superclass and all interfaces.
1145: // Also responsible for breaking inheritance cycles. This call
1146: // has been moved to 'resolveTypeStructure', just after the call
1147: // to 'resolveSupers', as inheritance cycles must be broken before
1148: // resolving types within the members. Fixes 4073739.
1149: // checkSupers(env);
1150:
1151: if (!isInterface()) {
1152:
1153: // Add implicit <init> method, if necessary.
1154: // QUERY: What keeps us from adding an implicit constructor
1155: // when the user explicitly declares one? Is it truly guaranteed
1156: // that the declaration for such an explicit constructor will have
1157: // been processed by the time we arrive here? In general, 'basicCheck'
1158: // is called very early, prior to the normal member checking phase.
1159: if (!hasConstructor()) {
1160: Node code = new CompoundStatement(getWhere(),
1161: new Statement[0]);
1162: Type t = Type.tMethod(Type.tVoid);
1163:
1164: // Default constructors inherit the access modifiers of their
1165: // class. For non-inner classes, this follows from JLS 8.6.7,
1166: // as the only possible modifier is 'public'. For the sake of
1167: // robustness in the presence of errors, we ignore any other
1168: // modifiers. For inner classes, the rule needs to be extended
1169: // in some way to account for the possibility of private and
1170: // protected classes. We make the 'obvious' extension, however,
1171: // the inner classes spec is silent on this issue, and a definitive
1172: // resolution is needed. See bugid 4087421.
1173: // WORKAROUND: A private constructor might need an access method,
1174: // but it is not possible to create one due to a restriction in
1175: // the verifier. (This is a known problem -- see 4015397.)
1176: // We therefore do not inherit the 'private' modifier from the class,
1177: // allowing the default constructor to be package private. This
1178: // workaround can be observed via reflection, but is otherwise
1179: // undetectable, as the constructor is always accessible within
1180: // the class in which its containing (private) class appears.
1181: int accessModifiers = getModifiers()
1182: & (isInnerClass() ? (M_PUBLIC | M_PROTECTED)
1183: : M_PUBLIC);
1184: env.makeMemberDefinition(env, getWhere(), this , null,
1185: accessModifiers, t, idInit, null, null, code);
1186: }
1187: }
1188:
1189: // Only do the inheritance/override checks if they are turned on.
1190: // The idea here is that they will be done in javac, but not
1191: // in javadoc. See the comment for turnOffChecks(), above.
1192: if (doInheritanceChecks) {
1193:
1194: // Verify the compatibility of all inherited method definitions
1195: // by collecting all of our inheritable methods.
1196: collectInheritedMethods(env);
1197: }
1198:
1199: basicChecking = false;
1200: basicCheckDone = true;
1201: if (tracing)
1202: env.dtExit("SourceClass.basicCheck: " + getName());
1203: }
1204:
1205: /**
1206: * Add a group of methods to this class as miranda methods.
1207: *
1208: * For a definition of Miranda methods, see the comment above the
1209: * method addMirandaMethods() in the file
1210: * sun/tools/java/ClassDeclaration.java
1211: */
1212: protected void addMirandaMethods(Environment env, Iterator mirandas) {
1213:
1214: while (mirandas.hasNext()) {
1215: MemberDefinition method = (MemberDefinition) mirandas
1216: .next();
1217:
1218: addMember(method);
1219:
1220: //System.out.println("adding miranda method " + newMethod +
1221: // " to " + this);
1222: }
1223: }
1224:
1225: /**
1226: * <em>After parsing is complete</em>, resolve all names
1227: * except those inside method bodies or initializers.
1228: * In particular, this is the point at which we find out what
1229: * kinds of variables and methods there are in the classes,
1230: * and therefore what is each class's interface to the world.
1231: * <p>
1232: * Also perform certain other transformations, such as inserting
1233: * "this$C" arguments into constructors, and reorganizing structure
1234: * to flatten qualified member names.
1235: * <p>
1236: * Do not perform type-based or name-based consistency checks
1237: * or normalizations (such as default nullary constructors),
1238: * and do not attempt to compile code against this class,
1239: * until after this phase.
1240: */
1241:
1242: private boolean resolving = false;
1243:
1244: public void resolveTypeStructure(Environment env) {
1245:
1246: if (tracing)
1247: env.dtEnter("SourceClass.resolveTypeStructure: "
1248: + getName());
1249:
1250: // Resolve immediately enclosing type, which in turn
1251: // forces resolution of all enclosing type declarations.
1252: ClassDefinition oc = getOuterClass();
1253: if (oc != null && oc instanceof SourceClass
1254: && !((SourceClass) oc).resolved) {
1255: // Do the outer class first, always.
1256: ((SourceClass) oc).resolveTypeStructure(env);
1257: // (Note: this.resolved is probably true at this point.)
1258: }
1259:
1260: // Punt if we've already resolved this class, or are currently
1261: // in the process of doing so.
1262: if (resolved || resolving) {
1263: if (tracing)
1264: env.dtExit("SourceClass.resolveTypeStructure: OK "
1265: + getName());
1266: return;
1267: }
1268:
1269: // Previously, 'resolved' was set here, and served to prevent
1270: // duplicate resolutions here as well as its function in
1271: // 'ClassDefinition.addMember'. Now, 'resolving' serves the
1272: // former purpose, distinct from that of 'resolved'.
1273: resolving = true;
1274:
1275: if (tracing)
1276: env.dtEvent("SourceClass.resolveTypeStructure: RESOLVING "
1277: + getName());
1278:
1279: env = setupEnv(env);
1280:
1281: // Resolve superclass names to class declarations
1282: // for the immediate superclass and superinterfaces.
1283: resolveSupers(env);
1284:
1285: // Check all ancestor superclasses for various
1286: // errors, verifying definition of all superclasses
1287: // and superinterfaces. Also breaks inheritance cycles.
1288: // Calls 'resolveTypeStructure' recursively for ancestors
1289: // This call used to appear in 'basicCheck', but was not
1290: // performed early enough. Most of the compiler will barf
1291: // on inheritance cycles!
1292: try {
1293: checkSupers(env);
1294: } catch (ClassNotFound ee) {
1295: // Undefined classes should be reported by 'checkSupers'.
1296: env.error(where, "class.not.found", ee.name, this );
1297: }
1298:
1299: for (MemberDefinition f = getFirstMember(); f != null; f = f
1300: .getNextMember()) {
1301: if (f instanceof SourceMember)
1302: ((SourceMember) f).resolveTypeStructure(env);
1303: }
1304:
1305: resolving = false;
1306:
1307: // Mark class as resolved. If new members are subsequently
1308: // added to the class, they will be resolved at that time.
1309: // See 'ClassDefinition.addMember'. Previously, this variable was
1310: // set prior to the calls to 'checkSupers' and 'resolveTypeStructure'
1311: // (which may engender further calls to 'checkSupers'). This could
1312: // lead to duplicate resolution of implicit constructors, as the call to
1313: // 'basicCheck' from 'checkSupers' could add the constructor while
1314: // its class is marked resolved, and thus would resolve the constructor,
1315: // believing it to be a "late addition". It would then be resolved
1316: // redundantly during the normal traversal of the members, which
1317: // immediately follows in the code above.
1318: resolved = true;
1319:
1320: // Now we have enough information to detect method repeats.
1321: for (MemberDefinition f = getFirstMember(); f != null; f = f
1322: .getNextMember()) {
1323: if (f.isInitializer())
1324: continue;
1325: if (!f.isMethod())
1326: continue;
1327: for (MemberDefinition f2 = f; (f2 = f2.getNextMatch()) != null;) {
1328: if (!f2.isMethod())
1329: continue;
1330: if (f.getType().equals(f2.getType())) {
1331: env.error(f.getWhere(), "meth.multidef", f);
1332: continue;
1333: }
1334: if (f.getType().equalArguments(f2.getType())) {
1335: env
1336: .error(f.getWhere(), "meth.redef.rettype",
1337: f, f2);
1338: continue;
1339: }
1340: }
1341: }
1342: if (tracing)
1343: env
1344: .dtExit("SourceClass.resolveTypeStructure: "
1345: + getName());
1346: }
1347:
1348: protected void resolveSupers(Environment env) {
1349: if (tracing)
1350: env.dtEnter("SourceClass.resolveSupers: " + this );
1351: // Find the super class
1352: if (super ClassId != null && super Class == null) {
1353: super Class = resolveSuper(env, super ClassId);
1354: // Special-case java.lang.Object here (not in the parser).
1355: // In all other cases, if we have a valid 'superClassId',
1356: // we return with a valid and non-null 'superClass' value.
1357: if (super Class == getClassDeclaration()
1358: && getName().equals(idJavaLangObject)) {
1359: super Class = null;
1360: super ClassId = null;
1361: }
1362: }
1363: // Find interfaces
1364: if (interfaceIds != null && interfaces == null) {
1365: interfaces = new ClassDeclaration[interfaceIds.length];
1366: for (int i = 0; i < interfaces.length; i++) {
1367: interfaces[i] = resolveSuper(env, interfaceIds[i]);
1368: for (int j = 0; j < i; j++) {
1369: if (interfaces[i] == interfaces[j]) {
1370: Identifier id = interfaceIds[i].getName();
1371: long where = interfaceIds[j].getWhere();
1372: env.error(where, "intf.repeated", id);
1373: }
1374: }
1375: }
1376: }
1377: if (tracing)
1378: env.dtExit("SourceClass.resolveSupers: " + this );
1379: }
1380:
1381: private ClassDeclaration resolveSuper(Environment env,
1382: IdentifierToken t) {
1383: Identifier name = t.getName();
1384: if (tracing)
1385: env.dtEnter("SourceClass.resolveSuper: " + name);
1386: if (isInnerClass())
1387: name = outerClass.resolveName(env, name);
1388: else
1389: name = env.resolveName(name);
1390: ClassDeclaration result = env.getClassDeclaration(name);
1391: // Result is never null, as a new 'ClassDeclaration' is
1392: // created if one with the given name does not exist.
1393: if (tracing)
1394: env.dtExit("SourceClass.resolveSuper: " + name);
1395: return result;
1396: }
1397:
1398: /**
1399: * During the type-checking of an outer method body or initializer,
1400: * this routine is called to check a local class body
1401: * in the proper context.
1402: * @param sup the named super class or interface (if anonymous)
1403: * @param args the actual arguments (if anonymous)
1404: */
1405: public Vset checkLocalClass(Environment env, Context ctx,
1406: Vset vset, ClassDefinition sup, Expression args[],
1407: Type argTypes[]) throws ClassNotFound {
1408: env = setupEnv(env);
1409:
1410: if ((sup != null) != isAnonymous()) {
1411: throw new CompilerError("resolveAnonymousStructure");
1412: }
1413: if (isAnonymous()) {
1414: resolveAnonymousStructure(env, sup, args, argTypes);
1415: }
1416:
1417: // Run the checks in the lexical context from the outer class.
1418: vset = checkInternal(env, ctx, vset);
1419:
1420: // This is now done by 'checkInternal' via its call to 'checkMembers'.
1421: // getClassDeclaration().setDefinition(this, CS_CHECKED);
1422:
1423: return vset;
1424: }
1425:
1426: /**
1427: * As with checkLocalClass, run the inline phase for a local class.
1428: */
1429: public void inlineLocalClass(Environment env) {
1430: for (MemberDefinition f = getFirstMember(); f != null; f = f
1431: .getNextMember()) {
1432: if ((f.isVariable() || f.isInitializer()) && !f.isStatic()) {
1433: continue; // inlined inside of constructors only
1434: }
1435: try {
1436: ((SourceMember) f).inline(env);
1437: } catch (ClassNotFound ee) {
1438: env.error(f.getWhere(), "class.not.found", ee.name,
1439: this );
1440: }
1441: }
1442: if (getReferencesFrozen() != null && !inlinedLocalClass) {
1443: inlinedLocalClass = true;
1444: // add more constructor arguments for uplevel references
1445: for (MemberDefinition f = getFirstMember(); f != null; f = f
1446: .getNextMember()) {
1447: if (f.isConstructor()) {
1448: //((SourceMember)f).addUplevelArguments(false);
1449: ((SourceMember) f).addUplevelArguments();
1450: }
1451: }
1452: }
1453: }
1454:
1455: private boolean inlinedLocalClass = false;
1456:
1457: /**
1458: * Check a class which is inside a local class, but is not itself local.
1459: */
1460: public Vset checkInsideClass(Environment env, Context ctx, Vset vset)
1461: throws ClassNotFound {
1462: if (!isInsideLocal() || isLocal()) {
1463: throw new CompilerError("checkInsideClass");
1464: }
1465: return checkInternal(env, ctx, vset);
1466: }
1467:
1468: /**
1469: * Just before checking an anonymous class, decide its true
1470: * inheritance, and build its (sole, implicit) constructor.
1471: */
1472: private void resolveAnonymousStructure(Environment env,
1473: ClassDefinition sup, Expression args[], Type argTypes[])
1474: throws ClassNotFound {
1475:
1476: if (tracing)
1477: env.dtEvent("SourceClass.resolveAnonymousStructure: "
1478: + this + ", super " + sup);
1479:
1480: // Decide now on the superclass.
1481:
1482: // This check has been removed as part of the fix for 4055017.
1483: // In the anonymous class created to hold the 'class$' method
1484: // of an interface, 'superClassId' refers to 'java.lang.Object'.
1485: /*---------------------*
1486: if (!(superClass == null && superClassId.getName() == idNull)) {
1487: throw new CompilerError("superclass "+superClass);
1488: }
1489: *---------------------*/
1490:
1491: if (sup.isInterface()) {
1492: // allow an interface in the "super class" position
1493: int ni = (interfaces == null) ? 0 : interfaces.length;
1494: ClassDeclaration i1[] = new ClassDeclaration[1 + ni];
1495: if (ni > 0) {
1496: System.arraycopy(interfaces, 0, i1, 1, ni);
1497: if (interfaceIds != null && interfaceIds.length == ni) {
1498: IdentifierToken id1[] = new IdentifierToken[1 + ni];
1499: System.arraycopy(interfaceIds, 0, id1, 1, ni);
1500: id1[0] = new IdentifierToken(sup.getName());
1501: }
1502: }
1503: i1[0] = sup.getClassDeclaration();
1504: interfaces = i1;
1505:
1506: sup = toplevelEnv.getClassDefinition(idJavaLangObject);
1507: }
1508: super Class = sup.getClassDeclaration();
1509:
1510: if (hasConstructor()) {
1511: throw new CompilerError("anonymous constructor");
1512: }
1513:
1514: // Synthesize an appropriate constructor.
1515: Type t = Type.tMethod(Type.tVoid, argTypes);
1516: IdentifierToken names[] = new IdentifierToken[argTypes.length];
1517: for (int i = 0; i < names.length; i++) {
1518: names[i] = new IdentifierToken(args[i].getWhere(),
1519: Identifier.lookup("$" + i));
1520: }
1521: int outerArg = (sup.isTopLevel() || sup.isLocal()) ? 0 : 1;
1522: Expression super Args[] = new Expression[-outerArg + args.length];
1523: for (int i = outerArg; i < args.length; i++) {
1524: super Args[-outerArg + i] = new IdentifierExpression(
1525: names[i]);
1526: }
1527: long where = getWhere();
1528: Expression super Exp;
1529: if (outerArg == 0) {
1530: super Exp = new SuperExpression(where);
1531: } else {
1532: super Exp = new SuperExpression(where,
1533: new IdentifierExpression(names[0]));
1534: }
1535: Expression super Call = new MethodExpression(where, super Exp,
1536: idInit, super Args);
1537: Statement body[] = { new ExpressionStatement(where, super Call) };
1538: Node code = new CompoundStatement(where, body);
1539: int mod = M_SYNTHETIC; // ISSUE: make M_PRIVATE, with wrapper?
1540: env.makeMemberDefinition(env, where, this , null, mod, t,
1541: idInit, names, null, code);
1542: }
1543:
1544: /**
1545: * Convert class modifiers to a string for diagnostic purposes.
1546: * Accepts modifiers applicable to inner classes and that appear
1547: * in the InnerClasses attribute only, as well as those that may
1548: * appear in the class modifier proper.
1549: */
1550:
1551: private static int classModifierBits[] = { ACC_PUBLIC, ACC_PRIVATE,
1552: ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_INTERFACE,
1553: ACC_ABSTRACT, ACC_SUPER, M_ANONYMOUS, M_LOCAL, M_STRICTFP,
1554: ACC_STRICT };
1555:
1556: private static String classModifierNames[] = { "PUBLIC", "PRIVATE",
1557: "PROTECTED", "STATIC", "FINAL", "INTERFACE", "ABSTRACT",
1558: "SUPER", "ANONYMOUS", "LOCAL", "STRICTFP", "STRICT" };
1559:
1560: static String classModifierString(int mods) {
1561: String s = "";
1562: for (int i = 0; i < classModifierBits.length; i++) {
1563: if ((mods & classModifierBits[i]) != 0) {
1564: s = s + " " + classModifierNames[i];
1565: mods &= ~classModifierBits[i];
1566: }
1567: }
1568: if (mods != 0) {
1569: s = s + " ILLEGAL:" + Integer.toHexString(mods);
1570: }
1571: return s;
1572: }
1573:
1574: /**
1575: * Find or create an access method for a private member,
1576: * or return null if this is not possible.
1577: */
1578: public MemberDefinition getAccessMember(Environment env,
1579: Context ctx, MemberDefinition field, boolean isSuper) {
1580: return getAccessMember(env, ctx, field, false, isSuper);
1581: }
1582:
1583: public MemberDefinition getUpdateMember(Environment env,
1584: Context ctx, MemberDefinition field, boolean isSuper) {
1585: if (!field.isVariable()) {
1586: throw new CompilerError("method");
1587: }
1588: return getAccessMember(env, ctx, field, true, isSuper);
1589: }
1590:
1591: private MemberDefinition getAccessMember(Environment env,
1592: Context ctx, MemberDefinition field, boolean isUpdate,
1593: boolean isSuper) {
1594:
1595: // The 'isSuper' argument is really only meaningful when the
1596: // target member is a method, in which case an 'invokespecial'
1597: // is needed. For fields, 'getfield' and 'putfield' instructions
1598: // are generated in either case, and 'isSuper' currently plays
1599: // no essential role. Nonetheless, we maintain the distinction
1600: // consistently for the time being.
1601:
1602: boolean isStatic = field.isStatic();
1603: boolean isMethod = field.isMethod();
1604:
1605: // Find pre-existing access method.
1606: // In the case of a field access method, we only look for the getter.
1607: // A getter is always created whenever a setter is.
1608: // QUERY: Why doesn't the 'MemberDefinition' object for the field
1609: // itself just have fields for its getter and setter?
1610: MemberDefinition af;
1611: for (af = getFirstMember(); af != null; af = af.getNextMember()) {
1612: if (af.getAccessMethodTarget() == field) {
1613: if (isMethod && af.isSuperAccessMethod() == isSuper) {
1614: break;
1615: }
1616: // Distinguish the getter and the setter by the number of
1617: // arguments.
1618: int nargs = af.getType().getArgumentTypes().length;
1619: // This was (nargs == (isStatic ? 0 : 1) + (isUpdate ? 1 : 0))
1620: // in order to find a setter as well as a getter. This caused
1621: // allocation of multiple getters.
1622: if (nargs == (isStatic ? 0 : 1)) {
1623: break;
1624: }
1625: }
1626: }
1627:
1628: if (af != null) {
1629: if (!isUpdate) {
1630: return af;
1631: } else {
1632: MemberDefinition uf = af.getAccessUpdateMember();
1633: if (uf != null) {
1634: return uf;
1635: }
1636: }
1637: } else if (isUpdate) {
1638: // must find or create the getter before creating the setter
1639: af = getAccessMember(env, ctx, field, false, isSuper);
1640: }
1641:
1642: // If we arrive here, we are creating a new access member.
1643:
1644: Identifier anm;
1645: Type dummyType = null;
1646:
1647: if (field.isConstructor()) {
1648: // For a constructor, we use the same name as for all
1649: // constructors ("<init>"), but add a distinguishing
1650: // argument of an otherwise unused "dummy" type.
1651: anm = idInit;
1652: // Get the dummy class, creating it if necessary.
1653: SourceClass outerMostClass = (SourceClass) getTopClass();
1654: dummyType = outerMostClass.dummyArgumentType;
1655: if (dummyType == null) {
1656: // Create dummy class.
1657: IdentifierToken sup = new IdentifierToken(0,
1658: idJavaLangObject);
1659: IdentifierToken interfaces[] = {};
1660: IdentifierToken t = new IdentifierToken(0, idNull);
1661: int mod = M_ANONYMOUS | M_STATIC | M_SYNTHETIC;
1662: // If an interface has a public inner class, the dummy class for
1663: // the constructor must always be accessible. Fix for 4221648.
1664: if (outerMostClass.isInterface()) {
1665: mod |= M_PUBLIC;
1666: }
1667: ClassDefinition dummyClass = toplevelEnv
1668: .makeClassDefinition(toplevelEnv, 0, t, null,
1669: mod, sup, interfaces, outerMostClass);
1670: // Check the class.
1671: // It is likely that a full check is not really necessary,
1672: // but it is essential that the class be marked as parsed.
1673: dummyClass.getClassDeclaration().setDefinition(
1674: dummyClass, CS_PARSED);
1675: Expression argsX[] = {};
1676: Type argTypesX[] = {};
1677: try {
1678: ClassDefinition supcls = toplevelEnv
1679: .getClassDefinition(idJavaLangObject);
1680: dummyClass.checkLocalClass(toplevelEnv, null,
1681: new Vset(), supcls, argsX, argTypesX);
1682: } catch (ClassNotFound ee) {
1683: }
1684: ;
1685: // Get class type.
1686: dummyType = dummyClass.getType();
1687: outerMostClass.dummyArgumentType = dummyType;
1688: }
1689: } else {
1690: // Otherwise, we use the name "access$N", for the
1691: // smallest value of N >= 0 yielding an unused name.
1692: for (int i = 0;; i++) {
1693: anm = Identifier.lookup(prefixAccess + i);
1694: if (getFirstMatch(anm) == null) {
1695: break;
1696: }
1697: }
1698: }
1699:
1700: Type argTypes[];
1701: Type t = field.getType();
1702:
1703: if (isStatic) {
1704: if (!isMethod) {
1705: if (!isUpdate) {
1706: Type at[] = {};
1707: argTypes = at;
1708: t = Type.tMethod(t); // nullary getter
1709: } else {
1710: Type at[] = { t };
1711: argTypes = at;
1712: t = Type.tMethod(Type.tVoid, argTypes); // unary setter
1713: }
1714: } else {
1715: // Since constructors are never static, we don't
1716: // have to worry about a dummy argument here.
1717: argTypes = t.getArgumentTypes();
1718: }
1719: } else {
1720: // All access methods for non-static members get an explicit
1721: // 'this' pointer as an extra argument, as the access methods
1722: // themselves must be static. EXCEPTION: Access methods for
1723: // constructors are non-static.
1724: Type classType = this .getType();
1725: if (!isMethod) {
1726: if (!isUpdate) {
1727: Type at[] = { classType };
1728: argTypes = at;
1729: t = Type.tMethod(t, argTypes); // nullary getter
1730: } else {
1731: Type at[] = { classType, t };
1732: argTypes = at;
1733: t = Type.tMethod(Type.tVoid, argTypes); // unary setter
1734: }
1735: } else {
1736: // Target is a method, possibly a constructor.
1737: Type at[] = t.getArgumentTypes();
1738: int nargs = at.length;
1739: if (field.isConstructor()) {
1740: // Access method is a constructor.
1741: // Requires a dummy argument.
1742: MemberDefinition outerThisArg = ((SourceMember) field)
1743: .getOuterThisArg();
1744: if (outerThisArg != null) {
1745: // Outer instance link must be the first argument.
1746: // The following is a sanity check that will catch
1747: // most cases in which in this requirement is violated.
1748: if (at[0] != outerThisArg.getType()) {
1749: throw new CompilerError(
1750: "misplaced outer this");
1751: }
1752: // Strip outer 'this' argument.
1753: // It will be added back when the access method is checked.
1754: argTypes = new Type[nargs];
1755: argTypes[0] = dummyType;
1756: for (int i = 1; i < nargs; i++) {
1757: argTypes[i] = at[i];
1758: }
1759: } else {
1760: // There is no outer instance.
1761: argTypes = new Type[nargs + 1];
1762: argTypes[0] = dummyType;
1763: for (int i = 0; i < nargs; i++) {
1764: argTypes[i + 1] = at[i];
1765: }
1766: }
1767: } else {
1768: // Access method is static.
1769: // Requires an explicit 'this' argument.
1770: argTypes = new Type[nargs + 1];
1771: argTypes[0] = classType;
1772: for (int i = 0; i < nargs; i++) {
1773: argTypes[i + 1] = at[i];
1774: }
1775: }
1776: t = Type.tMethod(t.getReturnType(), argTypes);
1777: }
1778: }
1779:
1780: int nlen = argTypes.length;
1781: long where = field.getWhere();
1782: IdentifierToken names[] = new IdentifierToken[nlen];
1783: for (int i = 0; i < nlen; i++) {
1784: names[i] = new IdentifierToken(where, Identifier.lookup("$"
1785: + i));
1786: }
1787:
1788: Expression access = null;
1789: Expression this Arg = null;
1790: Expression args[] = null;
1791:
1792: if (isStatic) {
1793: args = new Expression[nlen];
1794: for (int i = 0; i < nlen; i++) {
1795: args[i] = new IdentifierExpression(names[i]);
1796: }
1797: } else {
1798: if (field.isConstructor()) {
1799: // Constructor access method is non-static, so
1800: // 'this' works normally.
1801: this Arg = new ThisExpression(where);
1802: // Remove dummy argument, as it is not
1803: // passed to the target method.
1804: args = new Expression[nlen - 1];
1805: for (int i = 1; i < nlen; i++) {
1806: args[i - 1] = new IdentifierExpression(names[i]);
1807: }
1808: } else {
1809: // Non-constructor access method is static, so
1810: // we use the first argument as 'this'.
1811: this Arg = new IdentifierExpression(names[0]);
1812: // Remove first argument.
1813: args = new Expression[nlen - 1];
1814: for (int i = 1; i < nlen; i++) {
1815: args[i - 1] = new IdentifierExpression(names[i]);
1816: }
1817: }
1818: access = this Arg;
1819: }
1820:
1821: if (!isMethod) {
1822: access = new FieldExpression(where, access, field);
1823: if (isUpdate) {
1824: access = new AssignExpression(where, access, args[0]);
1825: }
1826: } else {
1827: // If true, 'isSuper' forces a non-virtual call.
1828: access = new MethodExpression(where, access, field, args,
1829: isSuper);
1830: }
1831:
1832: Statement code;
1833: if (t.getReturnType().isType(TC_VOID)) {
1834: code = new ExpressionStatement(where, access);
1835: } else {
1836: code = new ReturnStatement(where, access);
1837: }
1838: Statement body[] = { code };
1839: code = new CompoundStatement(where, body);
1840:
1841: // Access methods are now static (constructors excepted), and no longer final.
1842: // This change was mandated by the interaction of the access method
1843: // naming conventions and the restriction against overriding final
1844: // methods.
1845: int mod = M_SYNTHETIC;
1846: if (!field.isConstructor()) {
1847: mod |= M_STATIC;
1848: }
1849:
1850: // Create the synthetic method within the class in which the referenced
1851: // private member appears. The 'env' argument to 'makeMemberDefinition'
1852: // is suspect because it represents the environment at the point at
1853: // which a reference takes place, while it should represent the
1854: // environment in which the definition of the synthetic method appears.
1855: // We get away with this because 'env' is used only to access globals
1856: // such as 'Environment.error', and also as an argument to
1857: // 'resolveTypeStructure', which immediately discards it using
1858: // 'setupEnv'. Apparently, the current definition of 'setupEnv'
1859: // represents a design change that has not been thoroughly propagated.
1860: // An access method is declared with same list of exceptions as its
1861: // target. As the exceptions are simply listed by name, the correctness
1862: // of this approach requires that the access method be checked
1863: // (name-resolved) in the same context as its target method This
1864: // should always be the case.
1865: SourceMember newf = (SourceMember) env.makeMemberDefinition(
1866: env, where, this , null, mod, t, anm, names, field
1867: .getExceptionIds(), code);
1868: // Just to be safe, copy over the name-resolved exceptions from the
1869: // target so that the context in which the access method is checked
1870: // doesn't matter.
1871: newf.setExceptions(field.getExceptions(env));
1872:
1873: newf.setAccessMethodTarget(field);
1874: if (isUpdate) {
1875: af.setAccessUpdateMember(newf);
1876: }
1877: newf.setIsSuperAccessMethod(isSuper);
1878:
1879: // The call to 'check' is not needed, as the access method will be
1880: // checked by the containing class after it is added. This is the
1881: // idiom followed in the implementation of class literals. (See
1882: // 'FieldExpression.java'.) In any case, the context is wrong in the
1883: // call below. The access method must be checked in the context in
1884: // which it is declared, i.e., the class containing the referenced
1885: // private member, not the (inner) class in which the original member
1886: // reference occurs.
1887: //
1888: // try {
1889: // newf.check(env, ctx, new Vset());
1890: // } catch (ClassNotFound ee) {
1891: // env.error(where, "class.not.found", ee.name, this);
1892: // }
1893:
1894: // The comment above is inaccurate. While it is often the case
1895: // that the containing class will check the access method, this is
1896: // by no means guaranteed. In fact, an access method may be added
1897: // after the checking of its class is complete. In this case, however,
1898: // the context in which the class was checked will have been saved in
1899: // the class definition object (by the fix for 4095716), allowing us
1900: // to check the field now, and in the correct context.
1901: // This fixes bug 4098093.
1902:
1903: Context checkContext = newf.getClassDefinition()
1904: .getClassContext();
1905: if (checkContext != null) {
1906: //System.out.println("checking late addition: " + this);
1907: try {
1908: newf.check(env, checkContext, new Vset());
1909: } catch (ClassNotFound ee) {
1910: env.error(where, "class.not.found", ee.name, this );
1911: }
1912: }
1913:
1914: //System.out.println("[Access member '" +
1915: // newf + "' created for field '" +
1916: // field +"' in class '" + this + "']");
1917:
1918: return newf;
1919: }
1920:
1921: /**
1922: * Find an inner class of 'this', chosen arbitrarily.
1923: * Result is always an actual class, never an interface.
1924: * Returns null if none found.
1925: */
1926: SourceClass findLookupContext() {
1927: // Look for an immediate inner class.
1928: for (MemberDefinition f = getFirstMember(); f != null; f = f
1929: .getNextMember()) {
1930: if (f.isInnerClass()) {
1931: SourceClass ic = (SourceClass) f.getInnerClass();
1932: if (!ic.isInterface()) {
1933: return ic;
1934: }
1935: }
1936: }
1937: // Look for a class nested within an immediate inner interface.
1938: // At this point, we have given up on finding a minimally-nested
1939: // class (which would require a breadth-first traversal). It doesn't
1940: // really matter which inner class we find.
1941: for (MemberDefinition f = getFirstMember(); f != null; f = f
1942: .getNextMember()) {
1943: if (f.isInnerClass()) {
1944: SourceClass lc = ((SourceClass) f.getInnerClass())
1945: .findLookupContext();
1946: if (lc != null) {
1947: return lc;
1948: }
1949: }
1950: }
1951: // No inner classes.
1952: return null;
1953: }
1954:
1955: private MemberDefinition lookup = null;
1956:
1957: /**
1958: * Get helper method for class literal lookup.
1959: */
1960: public MemberDefinition getClassLiteralLookup(long fwhere) {
1961:
1962: // If we have already created a lookup method, reuse it.
1963: if (lookup != null) {
1964: return lookup;
1965: }
1966:
1967: // If the current class is a nested class, make sure we put the
1968: // lookup method in the outermost class. Set 'lookup' for the
1969: // intervening inner classes so we won't have to do the search
1970: // again.
1971: if (outerClass != null) {
1972: lookup = outerClass.getClassLiteralLookup(fwhere);
1973: return lookup;
1974: }
1975:
1976: // If we arrive here, there was no existing 'class$' method.
1977:
1978: ClassDefinition c = this ;
1979: boolean needNewClass = false;
1980:
1981: if (isInterface()) {
1982: // The top-level type is an interface. Try to find an existing
1983: // inner class in which to create the helper method. Any will do.
1984: c = findLookupContext();
1985: if (c == null) {
1986: // The interface has no inner classes. Create an anonymous
1987: // inner class to hold the helper method, as an interface must
1988: // not have any methods. The tests above for prior creation
1989: // of a 'class$' method assure that only one such class is
1990: // allocated for each outermost class containing a class
1991: // literal embedded somewhere within. Part of fix for 4055017.
1992: needNewClass = true;
1993: IdentifierToken sup = new IdentifierToken(fwhere,
1994: idJavaLangObject);
1995: IdentifierToken interfaces[] = {};
1996: IdentifierToken t = new IdentifierToken(fwhere, idNull);
1997: int mod = M_PUBLIC | M_ANONYMOUS | M_STATIC
1998: | M_SYNTHETIC;
1999: c = (SourceClass) toplevelEnv.makeClassDefinition(
2000: toplevelEnv, fwhere, t, null, mod, sup,
2001: interfaces, this );
2002: }
2003: }
2004:
2005: // The name of the class-getter stub is "class$"
2006: Identifier idDClass = Identifier.lookup(prefixClass);
2007: Type strarg[] = { Type.tString };
2008:
2009: // Some sanity checks of questionable value.
2010: //
2011: // This check became useless after matchMethod() was modified
2012: // to not return synthetic methods.
2013: //
2014: //try {
2015: // lookup = c.matchMethod(toplevelEnv, c, idDClass, strarg);
2016: //} catch (ClassNotFound ee) {
2017: // throw new CompilerError("unexpected missing class");
2018: //} catch (AmbiguousMember ee) {
2019: // throw new CompilerError("synthetic name clash");
2020: //}
2021: //if (lookup != null && lookup.getClassDefinition() == c) {
2022: // // Error if method found was not inherited.
2023: // throw new CompilerError("unexpected duplicate");
2024: //}
2025: // Some sanity checks of questionable value.
2026:
2027: /* // The helper function looks like this.
2028: * // It simply maps a checked exception to an unchecked one.
2029: * static Class class$(String class$) {
2030: * try { return Class.forName(class$); }
2031: * catch (ClassNotFoundException forName) {
2032: * throw new NoClassDefFoundError(forName.getMessage());
2033: * }
2034: * }
2035: */
2036: long w = c.getWhere();
2037: IdentifierToken arg = new IdentifierToken(w, idDClass);
2038: Expression e = new IdentifierExpression(arg);
2039: Expression a1[] = { e };
2040: Identifier idForName = Identifier.lookup("forName");
2041: e = new MethodExpression(w, new TypeExpression(w,
2042: Type.tClassDesc), idForName, a1);
2043: Statement body = new ReturnStatement(w, e);
2044: // map the exceptions
2045: Identifier idClassNotFound = Identifier
2046: .lookup("java.lang.ClassNotFoundException");
2047: Identifier idNoClassDefFound = Identifier
2048: .lookup("java.lang.NoClassDefFoundError");
2049: Type ctyp = Type.tClass(idClassNotFound);
2050: Type exptyp = Type.tClass(idNoClassDefFound);
2051: Identifier idGetMessage = Identifier.lookup("getMessage");
2052: e = new IdentifierExpression(w, idForName);
2053: e = new MethodExpression(w, e, idGetMessage, new Expression[0]);
2054: Expression a2[] = { e };
2055: e = new NewInstanceExpression(w, new TypeExpression(w, exptyp),
2056: a2);
2057: Statement handler = new CatchStatement(w, new TypeExpression(w,
2058: ctyp), new IdentifierToken(idForName),
2059: new ThrowStatement(w, e));
2060: Statement handlers[] = { handler };
2061: body = new TryStatement(w, body, handlers);
2062:
2063: Type mtype = Type.tMethod(Type.tClassDesc, strarg);
2064: IdentifierToken args[] = { arg };
2065:
2066: // Use default (package) access. If private, an access method would
2067: // be needed in the event that the class literal belonged to an interface.
2068: // Also, making it private tickles bug 4098316.
2069: lookup = toplevelEnv.makeMemberDefinition(toplevelEnv, w, c,
2070: null, M_STATIC | M_SYNTHETIC, mtype, idDClass, args,
2071: null, body);
2072:
2073: // If a new class was created to contain the helper method,
2074: // check it now.
2075: if (needNewClass) {
2076: if (c.getClassDeclaration().getStatus() == CS_CHECKED) {
2077: throw new CompilerError("duplicate check");
2078: }
2079: c.getClassDeclaration().setDefinition(c, CS_PARSED);
2080: Expression argsX[] = {};
2081: Type argTypesX[] = {};
2082: try {
2083: ClassDefinition sup = toplevelEnv
2084: .getClassDefinition(idJavaLangObject);
2085: c.checkLocalClass(toplevelEnv, null, new Vset(), sup,
2086: argsX, argTypesX);
2087: } catch (ClassNotFound ee) {
2088: }
2089: ;
2090: }
2091:
2092: return lookup;
2093: }
2094:
2095: /**
2096: * A list of active ongoing compilations. This list
2097: * is used to stop two compilations from saving the
2098: * same class.
2099: */
2100: private static Vector active = new Vector();
2101:
2102: /**
2103: * Compile this class
2104: */
2105: public void compile(OutputStream out) throws InterruptedException,
2106: IOException {
2107: Environment env = toplevelEnv;
2108: synchronized (active) {
2109: while (active.contains(getName())) {
2110: active.wait();
2111: }
2112: active.addElement(getName());
2113: }
2114:
2115: try {
2116: compileClass(env, out);
2117: } catch (ClassNotFound e) {
2118: throw new CompilerError(e);
2119: } finally {
2120: synchronized (active) {
2121: active.removeElement(getName());
2122: active.notifyAll();
2123: }
2124: }
2125: }
2126:
2127: /**
2128: * Verify that the modifier bits included in 'required' are
2129: * all present in 'mods', otherwise signal an internal error.
2130: * Note that errors in the source program may corrupt the modifiers,
2131: * thus we rely on the fact that 'CompilerError' exceptions are
2132: * silently ignored after an error message has been issued.
2133: */
2134: private static void assertModifiers(int mods, int required) {
2135: if ((mods & required) != required) {
2136: throw new CompilerError("illegal class modifiers");
2137: }
2138: }
2139:
2140: protected void compileClass(Environment env, OutputStream out)
2141: throws IOException, ClassNotFound {
2142: Vector variables = new Vector();
2143: Vector methods = new Vector();
2144: Vector innerClasses = new Vector();
2145: CompilerMember init = new CompilerMember(new MemberDefinition(
2146: getWhere(), this , M_STATIC, Type.tMethod(Type.tVoid),
2147: idClassInit, null, null), new Assembler());
2148: Context ctx = new Context((Context) null, init.field);
2149:
2150: for (ClassDefinition def = this ; def.isInnerClass(); def = def
2151: .getOuterClass()) {
2152: innerClasses.addElement(def);
2153: }
2154: // Reverse the order, so that outer levels come first:
2155: int ncsize = innerClasses.size();
2156: for (int i = ncsize; --i >= 0;)
2157: innerClasses.addElement(innerClasses.elementAt(i));
2158: for (int i = ncsize; --i >= 0;)
2159: innerClasses.removeElementAt(i);
2160:
2161: // System.out.println("compile class " + getName());
2162:
2163: boolean haveDeprecated = this .isDeprecated();
2164: boolean haveSynthetic = this .isSynthetic();
2165: boolean haveConstantValue = false;
2166: boolean haveExceptions = false;
2167:
2168: // Generate code for all fields
2169: for (SourceMember field = (SourceMember) getFirstMember(); field != null; field = (SourceMember) field
2170: .getNextMember()) {
2171:
2172: //System.out.println("compile field " + field.getName());
2173:
2174: haveDeprecated |= field.isDeprecated();
2175: haveSynthetic |= field.isSynthetic();
2176:
2177: try {
2178: if (field.isMethod()) {
2179: haveExceptions |= (field.getExceptions(env).length > 0);
2180:
2181: if (field.isInitializer()) {
2182: if (field.isStatic()) {
2183: field.code(env, init.asm);
2184: }
2185: } else {
2186: CompilerMember f = new CompilerMember(field,
2187: new Assembler());
2188: field.code(env, f.asm);
2189: methods.addElement(f);
2190: }
2191: } else if (field.isInnerClass()) {
2192: innerClasses.addElement(field.getInnerClass());
2193: } else if (field.isVariable()) {
2194: field.inline(env);
2195: CompilerMember f = new CompilerMember(field, null);
2196: variables.addElement(f);
2197: if (field.isStatic()) {
2198: field.codeInit(env, ctx, init.asm);
2199:
2200: }
2201: haveConstantValue |= (field.getInitialValue() != null);
2202: }
2203: } catch (CompilerError ee) {
2204: ee.printStackTrace();
2205: env
2206: .error(field, 0, "generic", field
2207: .getClassDeclaration()
2208: + ":" + field + "@" + ee.toString(),
2209: null, null);
2210: }
2211: }
2212: if (!init.asm.empty()) {
2213: init.asm.add(getWhere(), opc_return, true);
2214: methods.addElement(init);
2215: }
2216:
2217: // bail out if there were any errors
2218: if (getNestError()) {
2219: return;
2220: }
2221:
2222: int nClassAttrs = 0;
2223:
2224: // Insert constants
2225: if (methods.size() > 0) {
2226: tab.put("Code");
2227: }
2228: if (haveConstantValue) {
2229: tab.put("ConstantValue");
2230: }
2231:
2232: String sourceFile = null;
2233: if (env.debug_source()) {
2234: sourceFile = ((ClassFile) getSource()).getName();
2235: tab.put("SourceFile");
2236: tab.put(sourceFile);
2237: nClassAttrs += 1;
2238: }
2239:
2240: if (haveExceptions) {
2241: tab.put("Exceptions");
2242: }
2243:
2244: if (env.debug_lines()) {
2245: tab.put("LineNumberTable");
2246: }
2247: if (haveDeprecated) {
2248: tab.put("Deprecated");
2249: if (this .isDeprecated()) {
2250: nClassAttrs += 1;
2251: }
2252: }
2253: if (haveSynthetic) {
2254: tab.put("Synthetic");
2255: if (this .isSynthetic()) {
2256: nClassAttrs += 1;
2257: }
2258: }
2259: // JCOV
2260: if (env.coverage()) {
2261: nClassAttrs += 2; // AbsoluteSourcePath, TimeStamp
2262: tab.put("AbsoluteSourcePath");
2263: tab.put("TimeStamp");
2264: tab.put("CoverageTable");
2265: }
2266: // end JCOV
2267: if (env.debug_vars()) {
2268: tab.put("LocalVariableTable");
2269: }
2270: if (innerClasses.size() > 0) {
2271: tab.put("InnerClasses");
2272: nClassAttrs += 1; // InnerClasses
2273: }
2274:
2275: // JCOV
2276: String absoluteSourcePath = "";
2277: long timeStamp = 0;
2278:
2279: if (env.coverage()) {
2280: absoluteSourcePath = getAbsoluteName();
2281: timeStamp = System.currentTimeMillis();
2282: tab.put(absoluteSourcePath);
2283: }
2284: // end JCOV
2285: tab.put(getClassDeclaration());
2286: if (getSuperClass() != null) {
2287: tab.put(getSuperClass());
2288: }
2289: for (int i = 0; i < interfaces.length; i++) {
2290: tab.put(interfaces[i]);
2291: }
2292:
2293: // Sort the methods in order to make sure both constant pool
2294: // entries and methods are in a deterministic order from run
2295: // to run (this allows comparing class files for a fixed point
2296: // to validate the compiler)
2297: CompilerMember[] ordered_methods = new CompilerMember[methods
2298: .size()];
2299: methods.copyInto(ordered_methods);
2300: java.util.Arrays.sort(ordered_methods);
2301: for (int i = 0; i < methods.size(); i++)
2302: methods.setElementAt(ordered_methods[i], i);
2303:
2304: // Optimize Code and Collect method constants
2305: for (Enumeration e = methods.elements(); e.hasMoreElements();) {
2306: CompilerMember f = (CompilerMember) e.nextElement();
2307: try {
2308: f.asm.optimize(env);
2309: f.asm.collect(env, f.field, tab);
2310: tab.put(f.name);
2311: tab.put(f.sig);
2312: ClassDeclaration exp[] = f.field.getExceptions(env);
2313: for (int i = 0; i < exp.length; i++) {
2314: tab.put(exp[i]);
2315: }
2316: } catch (Exception ee) {
2317: ee.printStackTrace();
2318: env.error(f.field, -1, "generic", f.field.getName()
2319: + "@" + ee.toString(), null, null);
2320: f.asm.listing(System.out);
2321: }
2322: }
2323:
2324: // Collect field constants
2325: for (Enumeration e = variables.elements(); e.hasMoreElements();) {
2326: CompilerMember f = (CompilerMember) e.nextElement();
2327: tab.put(f.name);
2328: tab.put(f.sig);
2329:
2330: Object val = f.field.getInitialValue();
2331: if (val != null) {
2332: tab.put((val instanceof String) ? new StringExpression(
2333: f.field.getWhere(), (String) val) : val);
2334: }
2335: }
2336:
2337: // Collect inner class constants
2338: for (Enumeration e = innerClasses.elements(); e
2339: .hasMoreElements();) {
2340: ClassDefinition inner = (ClassDefinition) e.nextElement();
2341: tab.put(inner.getClassDeclaration());
2342:
2343: // If the inner class is local, we do not need to add its
2344: // outer class here -- the outer_class_info_index is zero.
2345: if (!inner.isLocal()) {
2346: ClassDefinition outer = inner.getOuterClass();
2347: tab.put(outer.getClassDeclaration());
2348: }
2349:
2350: // If the local name of the class is idNull, don't bother to
2351: // add it to the constant pool. We won't need it.
2352: Identifier inner_local_name = inner.getLocalName();
2353: if (inner_local_name != idNull) {
2354: tab.put(inner_local_name.toString());
2355: }
2356: }
2357:
2358: // Write header
2359: DataOutputStream data = new DataOutputStream(out);
2360: data.writeInt(JAVA_MAGIC);
2361: data.writeShort(toplevelEnv.getMinorVersion());
2362: data.writeShort(toplevelEnv.getMajorVersion());
2363: tab.write(env, data);
2364:
2365: // Write class information
2366: int cmods = getModifiers() & MM_CLASS;
2367:
2368: // Certain modifiers are implied:
2369: // 1. Any interface (nested or not) is implicitly deemed to be abstract,
2370: // whether it is explicitly marked so or not. (Java 1.0.)
2371: // 2. A interface which is a member of a type is implicitly deemed to
2372: // be static, whether it is explicitly marked so or not.
2373: // 3a. A type which is a member of an interface is implicitly deemed
2374: // to be public, whether it is explicitly marked so or not.
2375: // 3b. A type which is a member of an interface is implicitly deemed
2376: // to be static, whether it is explicitly marked so or not.
2377: // All of these rules are implemented in 'BatchParser.beginClass',
2378: // but the results are verified here.
2379:
2380: if (isInterface()) {
2381: // Rule 1.
2382: // The VM spec states that ACC_ABSTRACT must be set when
2383: // ACC_INTERFACE is; this was not done by javac prior to 1.2,
2384: // and the runtime compensates by setting it. Making sure
2385: // it is set here will allow the runtime hack to eventually
2386: // be removed. Rule 2 doesn't apply to transformed modifiers.
2387: assertModifiers(cmods, ACC_ABSTRACT);
2388: } else {
2389: // Contrary to the JVM spec, we only set ACC_SUPER for classes,
2390: // not interfaces. This is a workaround for a bug in IE3.0,
2391: // which refuses interfaces with ACC_SUPER on.
2392: cmods |= ACC_SUPER;
2393: }
2394:
2395: // If this is a nested class, transform access modifiers.
2396: if (outerClass != null) {
2397: // If private, transform to default (package) access.
2398: // If protected, transform to public.
2399: // M_PRIVATE and M_PROTECTED are already masked off by MM_CLASS above.
2400: // cmods &= ~(M_PRIVATE | M_PROTECTED);
2401: if (isProtected())
2402: cmods |= M_PUBLIC;
2403: // Rule 3a. Note that Rule 3b doesn't apply to transformed modifiers.
2404: if (outerClass.isInterface()) {
2405: assertModifiers(cmods, M_PUBLIC);
2406: }
2407: }
2408:
2409: data.writeShort(cmods);
2410:
2411: if (env.dumpModifiers()) {
2412: Identifier cn = getName();
2413: Identifier nm = Identifier.lookup(cn.getQualifier(), cn
2414: .getFlatName());
2415: System.out.println();
2416: System.out.println("CLASSFILE " + nm);
2417: System.out.println("---" + classModifierString(cmods));
2418: }
2419:
2420: data.writeShort(tab.index(getClassDeclaration()));
2421: data.writeShort((getSuperClass() != null) ? tab
2422: .index(getSuperClass()) : 0);
2423: data.writeShort(interfaces.length);
2424: for (int i = 0; i < interfaces.length; i++) {
2425: data.writeShort(tab.index(interfaces[i]));
2426: }
2427:
2428: // write variables
2429: ByteArrayOutputStream buf = new ByteArrayOutputStream(256);
2430: ByteArrayOutputStream attbuf = new ByteArrayOutputStream(256);
2431: DataOutputStream databuf = new DataOutputStream(buf);
2432:
2433: data.writeShort(variables.size());
2434: for (Enumeration e = variables.elements(); e.hasMoreElements();) {
2435: CompilerMember f = (CompilerMember) e.nextElement();
2436: Object val = f.field.getInitialValue();
2437:
2438: data.writeShort(f.field.getModifiers() & MM_FIELD);
2439: data.writeShort(tab.index(f.name));
2440: data.writeShort(tab.index(f.sig));
2441:
2442: int fieldAtts = (val != null ? 1 : 0);
2443: boolean dep = f.field.isDeprecated();
2444: boolean syn = f.field.isSynthetic();
2445: fieldAtts += (dep ? 1 : 0) + (syn ? 1 : 0);
2446:
2447: data.writeShort(fieldAtts);
2448: if (val != null) {
2449: data.writeShort(tab.index("ConstantValue"));
2450: data.writeInt(2);
2451: data
2452: .writeShort(tab
2453: .index((val instanceof String) ? new StringExpression(
2454: f.field.getWhere(),
2455: (String) val)
2456: : val));
2457: }
2458: if (dep) {
2459: data.writeShort(tab.index("Deprecated"));
2460: data.writeInt(0);
2461: }
2462: if (syn) {
2463: data.writeShort(tab.index("Synthetic"));
2464: data.writeInt(0);
2465: }
2466: }
2467:
2468: // write methods
2469:
2470: data.writeShort(methods.size());
2471: for (Enumeration e = methods.elements(); e.hasMoreElements();) {
2472: CompilerMember f = (CompilerMember) e.nextElement();
2473:
2474: int xmods = f.field.getModifiers() & MM_METHOD;
2475: // Transform floating point modifiers. M_STRICTFP
2476: // of member + status of enclosing class turn into
2477: // ACC_STRICT bit.
2478: if (((xmods & M_STRICTFP) != 0)
2479: || ((cmods & M_STRICTFP) != 0)) {
2480: xmods |= ACC_STRICT;
2481: } else {
2482: // Use the default
2483: if (env.strictdefault()) {
2484: xmods |= ACC_STRICT;
2485: }
2486: }
2487: data.writeShort(xmods);
2488:
2489: data.writeShort(tab.index(f.name));
2490: data.writeShort(tab.index(f.sig));
2491: ClassDeclaration exp[] = f.field.getExceptions(env);
2492: int methodAtts = ((exp.length > 0) ? 1 : 0);
2493: boolean dep = f.field.isDeprecated();
2494: boolean syn = f.field.isSynthetic();
2495: methodAtts += (dep ? 1 : 0) + (syn ? 1 : 0);
2496:
2497: if (!f.asm.empty()) {
2498: data.writeShort(methodAtts + 1);
2499: f.asm.write(env, databuf, f.field, tab);
2500: int natts = 0;
2501: if (env.debug_lines()) {
2502: natts++;
2503: }
2504: // JCOV
2505: if (env.coverage()) {
2506: natts++;
2507: }
2508: // end JCOV
2509: if (env.debug_vars()) {
2510: natts++;
2511: }
2512: databuf.writeShort(natts);
2513:
2514: if (env.debug_lines()) {
2515: f.asm.writeLineNumberTable(env,
2516: new DataOutputStream(attbuf), tab);
2517: databuf.writeShort(tab.index("LineNumberTable"));
2518: databuf.writeInt(attbuf.size());
2519: attbuf.writeTo(buf);
2520: attbuf.reset();
2521: }
2522:
2523: //JCOV
2524: if (env.coverage()) {
2525: f.asm.writeCoverageTable(env,
2526: (ClassDefinition) this ,
2527: new DataOutputStream(attbuf), tab, f.field
2528: .getWhere());
2529: databuf.writeShort(tab.index("CoverageTable"));
2530: databuf.writeInt(attbuf.size());
2531: attbuf.writeTo(buf);
2532: attbuf.reset();
2533: }
2534: // end JCOV
2535: if (env.debug_vars()) {
2536: f.asm.writeLocalVariableTable(env, f.field,
2537: new DataOutputStream(attbuf), tab);
2538: databuf.writeShort(tab.index("LocalVariableTable"));
2539: databuf.writeInt(attbuf.size());
2540: attbuf.writeTo(buf);
2541: attbuf.reset();
2542: }
2543:
2544: data.writeShort(tab.index("Code"));
2545: data.writeInt(buf.size());
2546: buf.writeTo(data);
2547: buf.reset();
2548: } else {
2549: //JCOV
2550: if ((env.coverage())
2551: && ((f.field.getModifiers() & M_NATIVE) > 0))
2552: f.asm.addNativeToJcovTab(env,
2553: (ClassDefinition) this );
2554: // end JCOV
2555: data.writeShort(methodAtts);
2556: }
2557:
2558: if (exp.length > 0) {
2559: data.writeShort(tab.index("Exceptions"));
2560: data.writeInt(2 + exp.length * 2);
2561: data.writeShort(exp.length);
2562: for (int i = 0; i < exp.length; i++) {
2563: data.writeShort(tab.index(exp[i]));
2564: }
2565: }
2566: if (dep) {
2567: data.writeShort(tab.index("Deprecated"));
2568: data.writeInt(0);
2569: }
2570: if (syn) {
2571: data.writeShort(tab.index("Synthetic"));
2572: data.writeInt(0);
2573: }
2574: }
2575:
2576: // class attributes
2577: data.writeShort(nClassAttrs);
2578:
2579: if (env.debug_source()) {
2580: data.writeShort(tab.index("SourceFile"));
2581: data.writeInt(2);
2582: data.writeShort(tab.index(sourceFile));
2583: }
2584:
2585: if (this .isDeprecated()) {
2586: data.writeShort(tab.index("Deprecated"));
2587: data.writeInt(0);
2588: }
2589: if (this .isSynthetic()) {
2590: data.writeShort(tab.index("Synthetic"));
2591: data.writeInt(0);
2592: }
2593:
2594: // JCOV
2595: if (env.coverage()) {
2596: data.writeShort(tab.index("AbsoluteSourcePath"));
2597: data.writeInt(2);
2598: data.writeShort(tab.index(absoluteSourcePath));
2599: data.writeShort(tab.index("TimeStamp"));
2600: data.writeInt(8);
2601: data.writeLong(timeStamp);
2602: }
2603: // end JCOV
2604:
2605: if (innerClasses.size() > 0) {
2606: data.writeShort(tab.index("InnerClasses"));
2607: data.writeInt(2 + 2 * 4 * innerClasses.size());
2608: data.writeShort(innerClasses.size());
2609: for (Enumeration e = innerClasses.elements(); e
2610: .hasMoreElements();) {
2611: // For each inner class name transformation, we have a record
2612: // with the following fields:
2613: //
2614: // u2 inner_class_info_index; // CONSTANT_Class_info index
2615: // u2 outer_class_info_index; // CONSTANT_Class_info index
2616: // u2 inner_name_index; // CONSTANT_Utf8_info index
2617: // u2 inner_class_access_flags; // access_flags bitmask
2618: //
2619: // The spec states that outer_class_info_index is 0 iff
2620: // the inner class is not a member of its enclosing class (i.e.
2621: // it is a local or anonymous class). The spec also states
2622: // that if a class is anonymous then inner_name_index should
2623: // be 0.
2624: //
2625: // See also the initInnerClasses() method in BinaryClass.java.
2626:
2627: // Generate inner_class_info_index.
2628: ClassDefinition inner = (ClassDefinition) e
2629: .nextElement();
2630: data.writeShort(tab.index(inner.getClassDeclaration()));
2631:
2632: // Generate outer_class_info_index.
2633: //
2634: // Checking isLocal() should probably be enough here,
2635: // but the check for isAnonymous is added for good
2636: // measure.
2637: if (inner.isLocal() || inner.isAnonymous()) {
2638: data.writeShort(0);
2639: } else {
2640: // Query: what about if inner.isInsideLocal()?
2641: // For now we continue to generate a nonzero
2642: // outer_class_info_index.
2643: ClassDefinition outer = inner.getOuterClass();
2644: data.writeShort(tab.index(outer
2645: .getClassDeclaration()));
2646: }
2647:
2648: // Generate inner_name_index.
2649: Identifier inner_name = inner.getLocalName();
2650: if (inner_name == idNull) {
2651: if (!inner.isAnonymous()) {
2652: throw new CompilerError(
2653: "compileClass(), anonymous");
2654: }
2655: data.writeShort(0);
2656: } else {
2657: data.writeShort(tab.index(inner_name.toString()));
2658: }
2659:
2660: // Generate inner_class_access_flags.
2661: int imods = inner.getInnerClassMember().getModifiers()
2662: & ACCM_INNERCLASS;
2663:
2664: // Certain modifiers are implied for nested types.
2665: // See rules 1, 2, 3a, and 3b enumerated above.
2666: // All of these rules are implemented in 'BatchParser.beginClass',
2667: // but are verified here.
2668:
2669: if (inner.isInterface()) {
2670: // Rules 1 and 2.
2671: assertModifiers(imods, M_ABSTRACT | M_STATIC);
2672: }
2673: if (inner.getOuterClass().isInterface()) {
2674: // Rules 3a and 3b.
2675: imods &= ~(M_PRIVATE | M_PROTECTED); // error recovery
2676: assertModifiers(imods, M_PUBLIC | M_STATIC);
2677: }
2678:
2679: data.writeShort(imods);
2680:
2681: if (env.dumpModifiers()) {
2682: Identifier fn = inner.getInnerClassMember()
2683: .getName();
2684: Identifier nm = Identifier.lookup(
2685: fn.getQualifier(), fn.getFlatName());
2686: System.out.println("INNERCLASS " + nm);
2687: System.out.println("---"
2688: + classModifierString(imods));
2689: }
2690:
2691: }
2692: }
2693:
2694: // Cleanup
2695: data.flush();
2696: tab = null;
2697:
2698: // JCOV
2699: // generate coverage data
2700: if (env.covdata()) {
2701: Assembler CovAsm = new Assembler();
2702: CovAsm.GenVecJCov(env, (ClassDefinition) this , timeStamp);
2703: }
2704: // end JCOV
2705: }
2706:
2707: /**
2708: * Print out the dependencies for this class (-xdepend) option
2709: */
2710:
2711: public void printClassDependencies(Environment env) {
2712:
2713: // Only do this if the -xdepend flag is on
2714: if (toplevelEnv.print_dependencies()) {
2715:
2716: // Name of java source file this class was in (full path)
2717: // e.g. /home/ohair/Test.java
2718: String src = ((ClassFile) getSource()).getAbsoluteName();
2719:
2720: // Class name, fully qualified
2721: // e.g. "java.lang.Object" or "FooBar" or "sun.tools.javac.Main"
2722: // Inner class names must be mangled, as ordinary '.' qualification
2723: // is used internally where the spec requires '$' separators.
2724: // String className = getName().toString();
2725: String className = Type.mangleInnerType(getName())
2726: .toString();
2727:
2728: // Line number where class starts in the src file
2729: long startLine = getWhere() >> WHEREOFFSETBITS;
2730:
2731: // Line number where class ends in the src file (not used yet)
2732: long endLine = getEndPosition() >> WHEREOFFSETBITS;
2733:
2734: // First line looks like:
2735: // CLASS:src,startLine,endLine,className
2736: System.out.println("CLASS:" + src + "," + startLine + ","
2737: + endLine + "," + className);
2738:
2739: // For each class this class is dependent on:
2740: // CLDEP:className1,className2
2741: // where className1 is the name of the class we are in, and
2742: // classname2 is the name of the class className1
2743: // is dependent on.
2744: for (Enumeration e = deps.elements(); e.hasMoreElements();) {
2745: ClassDeclaration data = (ClassDeclaration) e
2746: .nextElement();
2747: // Mangle name of class dependend on.
2748: String depName = Type.mangleInnerType(data.getName())
2749: .toString();
2750: env.output("CLDEP:" + className + "," + depName);
2751: }
2752: }
2753: }
2754: }
|