Showing the changes to java/pkg/sun/tools/java (33 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,53 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This exception is thrown when an unqualified class name | |
| 30 | + * is used that can be resolved in more than one way. | |
| 31 | + * | |
| 32 | + * WARNING: The contents of this source file are not part of any | |
| 33 | + * supported API. Code that depends on them does so at its own risk: | |
| 34 | + * they are subject to change or removal without notice. | |
| 35 | + */ | |
| 36 | + | |
| 37 | +public | |
| 38 | +class AmbiguousClass extends ClassNotFound { | |
| 39 | + /** | |
| 40 | + * The class that was not found | |
| 41 | + */ | |
| 42 | + public Identifier name1; | |
| 43 | + public Identifier name2; | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * Constructor | |
| 47 | + */ | |
| 48 | + public AmbiguousClass(Identifier name1, Identifier name2) { | |
| 49 | + super(name1.getName()); | |
| 50 | + this.name1 = name1; | |
| 51 | + this.name2 = name2; | |
| 52 | + } | |
| 53 | +} | |
| @@ -0,0 +1,54 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +import java.util.Enumeration; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * This exception is thrown when a field reference is | |
| 32 | + * ambiguous. | |
| 33 | + * | |
| 34 | + * WARNING: The contents of this source file are not part of any | |
| 35 | + * supported API. Code that depends on them does so at its own risk: | |
| 36 | + * they are subject to change or removal without notice. | |
| 37 | + */ | |
| 38 | +public | |
| 39 | +class AmbiguousMember extends Exception { | |
| 40 | + /** | |
| 41 | + * The field that was not found | |
| 42 | + */ | |
| 43 | + public MemberDefinition field1; | |
| 44 | + public MemberDefinition field2; | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * Constructor | |
| 48 | + */ | |
| 49 | + public AmbiguousMember(MemberDefinition field1, MemberDefinition field2) { | |
| 50 | + super(field1.getName() + " + " + field2.getName()); | |
| 51 | + this.field1 = field1; | |
| 52 | + this.field2 = field2; | |
| 53 | + } | |
| 54 | +} | |
| @@ -0,0 +1,65 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This class represents an Java array type. | |
| 30 | + * It overrides the relevant methods in class Type. | |
| 31 | + * | |
| 32 | + * WARNING: The contents of this source file are not part of any | |
| 33 | + * supported API. Code that depends on them does so at its own risk: | |
| 34 | + * they are subject to change or removal without notice. | |
| 35 | + * | |
| 36 | + * @author Arthur van Hoff | |
| 37 | + */ | |
| 38 | +public final | |
| 39 | +class ArrayType extends Type { | |
| 40 | + /** | |
| 41 | + * The type of the element. | |
| 42 | + */ | |
| 43 | + Type elemType; | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * Construct an array type. Use Type.tArray to create | |
| 47 | + * a new array type. | |
| 48 | + */ | |
| 49 | + ArrayType(String typeSig, Type elemType) { | |
| 50 | + super(TC_ARRAY, typeSig); | |
| 51 | + this.elemType = elemType; | |
| 52 | + } | |
| 53 | + | |
| 54 | + public Type getElementType() { | |
| 55 | + return elemType; | |
| 56 | + } | |
| 57 | + | |
| 58 | + public int getArrayDimension() { | |
| 59 | + return elemType.getArrayDimension() + 1; | |
| 60 | + } | |
| 61 | + | |
| 62 | + public String typeString(String id, boolean abbrev, boolean ret) { | |
| 63 | + return getElementType().typeString(id, abbrev, ret) + "[]"; | |
| 64 | + } | |
| 65 | +} | |
| @@ -0,0 +1,112 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +import java.io.IOException; | |
| 29 | +import java.io.DataInputStream; | |
| 30 | +import java.io.DataOutputStream; | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * This class is used to represent an attribute from a binary class. | |
| 34 | + * This class should go away once arrays are objects. | |
| 35 | + * | |
| 36 | + * WARNING: The contents of this source file are not part of any | |
| 37 | + * supported API. Code that depends on them does so at its own risk: | |
| 38 | + * they are subject to change or removal without notice. | |
| 39 | + */ | |
| 40 | +public final | |
| 41 | +class BinaryAttribute implements Constants { | |
| 42 | + Identifier name; | |
| 43 | + byte data[]; | |
| 44 | + BinaryAttribute next; | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * Constructor | |
| 48 | + */ | |
| 49 | + BinaryAttribute(Identifier name, byte data[], BinaryAttribute next) { | |
| 50 | + this.name = name; | |
| 51 | + this.data = data; | |
| 52 | + this.next = next; | |
| 53 | + } | |
| 54 | + | |
| 55 | + /** | |
| 56 | + * Load a list of attributes | |
| 57 | + */ | |
| 58 | + public static BinaryAttribute load(DataInputStream in, BinaryConstantPool cpool, int mask) throws IOException { | |
| 59 | + BinaryAttribute atts = null; | |
| 60 | + int natt = in.readUnsignedShort(); // JVM 4.6 method_info.attrutes_count | |
| 61 | + | |
| 62 | + for (int i = 0 ; i < natt ; i++) { | |
| 63 | + // id from JVM 4.7 attribute_info.attribute_name_index | |
| 64 | + Identifier id = cpool.getIdentifier(in.readUnsignedShort()); | |
| 65 | + // id from JVM 4.7 attribute_info.attribute_length | |
| 66 | + int len = in.readInt(); | |
| 67 | + | |
| 68 | + if (id.equals(idCode) && ((mask & ATT_CODE) == 0)) { | |
| 69 | + in.skipBytes(len); | |
| 70 | + } else { | |
| 71 | + byte data[] = new byte[len]; | |
| 72 | + in.readFully(data); | |
| 73 | + atts = new BinaryAttribute(id, data, atts); | |
| 74 | + } | |
| 75 | + } | |
| 76 | + return atts; | |
| 77 | + } | |
| 78 | + | |
| 79 | + // write out the Binary attributes to the given stream | |
| 80 | + // (note that attributes may be null) | |
| 81 | + static void write(BinaryAttribute attributes, DataOutputStream out, | |
| 82 | + BinaryConstantPool cpool, Environment env) throws IOException { | |
| 83 | + // count the number of attributes | |
| 84 | + int attributeCount = 0; | |
| 85 | + for (BinaryAttribute att = attributes; att != null; att = att.next) | |
| 86 | + attributeCount++; | |
| 87 | + out.writeShort(attributeCount); | |
| 88 | + | |
| 89 | + // write out each attribute | |
| 90 | + for (BinaryAttribute att = attributes; att != null; att = att.next) { | |
| 91 | + Identifier name = att.name; | |
| 92 | + byte data[] = att.data; | |
| 93 | + // write the identifier | |
| 94 | + out.writeShort(cpool.indexString(name.toString(), env)); | |
| 95 | + // write the length | |
| 96 | + out.writeInt(data.length); | |
| 97 | + // write the data | |
| 98 | + out.write(data, 0, data.length); | |
| 99 | + } | |
| 100 | + } | |
| 101 | + | |
| 102 | + /** | |
| 103 | + * Accessors | |
| 104 | + */ | |
| 105 | + | |
| 106 | + public Identifier getName() { return name; } | |
| 107 | + | |
| 108 | + public byte getData()[] { return data; } | |
| 109 | + | |
| 110 | + public BinaryAttribute getNextAttribute() { return next; } | |
| 111 | + | |
| 112 | +} | |
| @@ -0,0 +1,534 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +import java.io.IOException; | |
| 29 | +import java.io.DataInputStream; | |
| 30 | +import java.io.OutputStream; | |
| 31 | +import java.io.DataOutputStream; | |
| 32 | +import java.io.ByteArrayInputStream; | |
| 33 | +import java.util.Hashtable; | |
| 34 | +import java.util.Vector; | |
| 35 | +import java.util.Enumeration; | |
| 36 | + | |
| 37 | +/** | |
| 38 | + * WARNING: The contents of this source file are not part of any | |
| 39 | + * supported API. Code that depends on them does so at its own risk: | |
| 40 | + * they are subject to change or removal without notice. | |
| 41 | + */ | |
| 42 | +public final | |
| 43 | +class BinaryClass extends ClassDefinition implements Constants { | |
| 44 | + BinaryConstantPool cpool; | |
| 45 | + BinaryAttribute atts; | |
| 46 | + Vector dependencies; | |
| 47 | + private boolean haveLoadedNested = false; | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * Constructor | |
| 51 | + */ | |
| 52 | + public BinaryClass(Object source, ClassDeclaration declaration, int modifiers, | |
| 53 | + ClassDeclaration superClass, ClassDeclaration interfaces[], | |
| 54 | + Vector dependencies) { | |
| 55 | + super(source, 0, declaration, modifiers, null, null); | |
| 56 | + this.dependencies = dependencies; | |
| 57 | + this.superClass = superClass; | |
| 58 | + this.interfaces = interfaces; | |
| 59 | + } | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * Flags used by basicCheck() to avoid duplicate calls. | |
| 63 | + * (Part of fix for 4105911) | |
| 64 | + */ | |
| 65 | + private boolean basicCheckDone = false; | |
| 66 | + private boolean basicChecking = false; | |
| 67 | + | |
| 68 | + /** | |
| 69 | + * Ready a BinaryClass for further checking. Note that, until recently, | |
| 70 | + * BinaryClass relied on the default basicCheck() provided by | |
| 71 | + * ClassDefinition. The definition here has been added to ensure that | |
| 72 | + * the information generated by collectInheritedMethods is available | |
| 73 | + * for BinaryClasses. | |
| 74 | + */ | |
| 75 | + protected void basicCheck(Environment env) throws ClassNotFound { | |
| 76 | + if (tracing) env.dtEnter("BinaryClass.basicCheck: " + getName()); | |
| 77 | + | |
| 78 | + // We need to guard against duplicate calls to basicCheck(). They | |
| 79 | + // can lead to calling collectInheritedMethods() for this class | |
| 80 | + // from within a previous call to collectInheritedMethods() for | |
| 81 | + // this class. That is not allowed. | |
| 82 | + // (Part of fix for 4105911) | |
| 83 | + if (basicChecking || basicCheckDone) { | |
| 84 | + if (tracing) env.dtExit("BinaryClass.basicCheck: OK " + getName()); | |
| 85 | + return; | |
| 86 | + } | |
| 87 | + | |
| 88 | + if (tracing) env.dtEvent("BinaryClass.basicCheck: CHECKING " + getName()); | |
| 89 | + basicChecking = true; | |
| 90 | + | |
| 91 | + super.basicCheck(env); | |
| 92 | + | |
| 93 | + // Collect inheritance information. | |
| 94 | + if (doInheritanceChecks) { | |
| 95 | + collectInheritedMethods(env); | |
| 96 | + } | |
| 97 | + | |
| 98 | + basicCheckDone = true; | |
| 99 | + basicChecking = false; | |
| 100 | + if (tracing) env.dtExit("BinaryClass.basicCheck: " + getName()); | |
| 101 | + } | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * Load a binary class | |
| 105 | + */ | |
| 106 | + public static BinaryClass load(Environment env, DataInputStream in) throws IOException { | |
| 107 | + return load(env, in, ~(ATT_CODE|ATT_ALLCLASSES)); | |
| 108 | + } | |
| 109 | + | |
| 110 | + public static BinaryClass load(Environment env, | |
| 111 | + DataInputStream in, int mask) throws IOException { | |
| 112 | + // Read the header | |
| 113 | + int magic = in.readInt(); // JVM 4.1 ClassFile.magic | |
| 114 | + if (magic != JAVA_MAGIC) { | |
| 115 | + throw new ClassFormatError("wrong magic: " + magic + ", expected " + JAVA_MAGIC); | |
| 116 | + } | |
| 117 | + int minor_version = in.readUnsignedShort(); // JVM 4.1 ClassFile.minor_version | |
| 118 | + int version = in.readUnsignedShort(); // JVM 4.1 ClassFile.major_version | |
| 119 | + if (version < JAVA_MIN_SUPPORTED_VERSION) { | |
| 120 | + throw new ClassFormatError( | |
| 121 | + sun.tools.javac.Main.getText( | |
| 122 | + "javac.err.version.too.old", | |
| 123 | + String.valueOf(version))); | |
| 124 | + } else if ((version > JAVA_MAX_SUPPORTED_VERSION) | |
| 125 | + || (version == JAVA_MAX_SUPPORTED_VERSION | |
| 126 | + && minor_version > JAVA_MAX_SUPPORTED_MINOR_VERSION)) { | |
| 127 | + throw new ClassFormatError( | |
| 128 | + sun.tools.javac.Main.getText( | |
| 129 | + "javac.err.version.too.recent", | |
| 130 | + version+"."+minor_version)); | |
| 131 | + } | |
| 132 | + | |
| 133 | + // Read the constant pool | |
| 134 | + BinaryConstantPool cpool = new BinaryConstantPool(in); | |
| 135 | + | |
| 136 | + // The dependencies of this class | |
| 137 | + Vector dependencies = cpool.getDependencies(env); | |
| 138 | + | |
| 139 | + // Read modifiers | |
| 140 | + int classMod = in.readUnsignedShort() & ACCM_CLASS; // JVM 4.1 ClassFile.access_flags | |
| 141 | + | |
| 142 | + // Read the class name - from JVM 4.1 ClassFile.this_class | |
| 143 | + ClassDeclaration classDecl = cpool.getDeclaration(env, in.readUnsignedShort()); | |
| 144 | + | |
| 145 | + // Read the super class name (may be null) - from JVM 4.1 ClassFile.super_class | |
| 146 | + ClassDeclaration superClassDecl = cpool.getDeclaration(env, in.readUnsignedShort()); | |
| 147 | + | |
| 148 | + // Read the interface names - from JVM 4.1 ClassFile.interfaces_count | |
| 149 | + ClassDeclaration interfaces[] = new ClassDeclaration[in.readUnsignedShort()]; | |
| 150 | + for (int i = 0 ; i < interfaces.length ; i++) { | |
| 151 | + // JVM 4.1 ClassFile.interfaces[] | |
| 152 | + interfaces[i] = cpool.getDeclaration(env, in.readUnsignedShort()); | |
| 153 | + } | |
| 154 | + | |
| 155 | + // Allocate the class | |
| 156 | + BinaryClass c = new BinaryClass(null, classDecl, classMod, superClassDecl, | |
| 157 | + interfaces, dependencies); | |
| 158 | + c.cpool = cpool; | |
| 159 | + | |
| 160 | + // Add any additional dependencies | |
| 161 | + c.addDependency(superClassDecl); | |
| 162 | + | |
| 163 | + // Read the fields | |
| 164 | + int nfields = in.readUnsignedShort(); // JVM 4.1 ClassFile.fields_count | |
| 165 | + for (int i = 0 ; i < nfields ; i++) { | |
| 166 | + // JVM 4.5 field_info.access_flags | |
| 167 | + int fieldMod = in.readUnsignedShort() & ACCM_FIELD; | |
| 168 | + // JVM 4.5 field_info.name_index | |
| 169 | + Identifier fieldName = cpool.getIdentifier(in.readUnsignedShort()); | |
| 170 | + // JVM 4.5 field_info.descriptor_index | |
| 171 | + Type fieldType = cpool.getType(in.readUnsignedShort()); | |
| 172 | + BinaryAttribute atts = BinaryAttribute.load(in, cpool, mask); | |
| 173 | + c.addMember(new BinaryMember(c, fieldMod, fieldType, fieldName, atts)); | |
| 174 | + } | |
| 175 | + | |
| 176 | + // Read the methods | |
| 177 | + int nmethods = in.readUnsignedShort(); // JVM 4.1 ClassFile.methods_count | |
| 178 | + for (int i = 0 ; i < nmethods ; i++) { | |
| 179 | + // JVM 4.6 method_info.access_flags | |
| 180 | + int methMod = in.readUnsignedShort() & ACCM_METHOD; | |
| 181 | + // JVM 4.6 method_info.name_index | |
| 182 | + Identifier methName = cpool.getIdentifier(in.readUnsignedShort()); | |
| 183 | + // JVM 4.6 method_info.descriptor_index | |
| 184 | + Type methType = cpool.getType(in.readUnsignedShort()); | |
| 185 | + BinaryAttribute atts = BinaryAttribute.load(in, cpool, mask); | |
| 186 | + c.addMember(new BinaryMember(c, methMod, methType, methName, atts)); | |
| 187 | + } | |
| 188 | + | |
| 189 | + // Read the class attributes | |
| 190 | + c.atts = BinaryAttribute.load(in, cpool, mask); | |
| 191 | + | |
| 192 | + // See if the SourceFile is known | |
| 193 | + byte data[] = c.getAttribute(idSourceFile); | |
| 194 | + if (data != null) { | |
| 195 | + DataInputStream dataStream = new DataInputStream(new ByteArrayInputStream(data)); | |
| 196 | + // JVM 4.7.2 SourceFile_attribute.sourcefile_index | |
| 197 | + c.source = cpool.getString(dataStream.readUnsignedShort()); | |
| 198 | + } | |
| 199 | + | |
| 200 | + // See if the Documentation is know | |
| 201 | + data = c.getAttribute(idDocumentation); | |
| 202 | + if (data != null) { | |
| 203 | + c.documentation = new DataInputStream(new ByteArrayInputStream(data)).readUTF(); | |
| 204 | + } | |
| 205 | + | |
| 206 | + // Was it compiled as deprecated? | |
| 207 | + if (c.getAttribute(idDeprecated) != null) { | |
| 208 | + c.modifiers |= M_DEPRECATED; | |
| 209 | + } | |
| 210 | + | |
| 211 | + // Was it synthesized by the compiler? | |
| 212 | + if (c.getAttribute(idSynthetic) != null) { | |
| 213 | + c.modifiers |= M_SYNTHETIC; | |
| 214 | + } | |
| 215 | + | |
| 216 | + return c; | |
| 217 | + } | |
| 218 | + | |
| 219 | + /** | |
| 220 | + * Called when an environment ties a binary definition to a declaration. | |
| 221 | + * At this point, auxiliary definitions may be loaded. | |
| 222 | + */ | |
| 223 | + | |
| 224 | + public void loadNested(Environment env) { | |
| 225 | + loadNested(env, 0); | |
| 226 | + } | |
| 227 | + | |
| 228 | + public void loadNested(Environment env, int flags) { | |
| 229 | + // Sanity check. | |
| 230 | + if (haveLoadedNested) { | |
| 231 | + // Duplicate calls most likely should not occur, but they do | |
| 232 | + // in javap. Be tolerant of them for the time being. | |
| 233 | + // throw new CompilerError("multiple loadNested"); | |
| 234 | + if (tracing) env.dtEvent("loadNested: DUPLICATE CALL SKIPPED"); | |
| 235 | + return; | |
| 236 | + } | |
| 237 | + haveLoadedNested = true; | |
| 238 | + // Read class-nesting information. | |
| 239 | + try { | |
| 240 | + byte data[]; | |
| 241 | + data = getAttribute(idInnerClasses); | |
| 242 | + if (data != null) { | |
| 243 | + initInnerClasses(env, data, flags); | |
| 244 | + } | |
| 245 | + } catch (IOException ee) { | |
| 246 | + // The inner classes attribute is not well-formed. | |
| 247 | + // It may, for example, contain no data. Report this. | |
| 248 | + // We used to throw a CompilerError here (bug 4095108). | |
| 249 | + env.error(0, "malformed.attribute", getClassDeclaration(), | |
| 250 | + idInnerClasses); | |
| 251 | + if (tracing) | |
| 252 | + env.dtEvent("loadNested: MALFORMED ATTRIBUTE (InnerClasses)"); | |
| 253 | + } | |
| 254 | + } | |
| 255 | + | |
| 256 | + private void initInnerClasses(Environment env, | |
| 257 | + byte data[], | |
| 258 | + int flags) throws IOException { | |
| 259 | + DataInputStream ds = new DataInputStream(new ByteArrayInputStream(data)); | |
| 260 | + int nrec = ds.readUnsignedShort(); // InnerClasses_attribute.number_of_classes | |
| 261 | + for (int i = 0; i < nrec; i++) { | |
| 262 | + // For each inner class name transformation, we have a record | |
| 263 | + // with the following fields: | |
| 264 | + // | |
| 265 | + // u2 inner_class_info_index; // CONSTANT_Class_info index | |
| 266 | + // u2 outer_class_info_index; // CONSTANT_Class_info index | |
| 267 | + // u2 inner_name_index; // CONSTANT_Utf8_info index | |
| 268 | + // u2 inner_class_access_flags; // access_flags bitmask | |
| 269 | + // | |
| 270 | + // The spec states that outer_class_info_index is 0 iff | |
| 271 | + // the inner class is not a member of its enclosing class (i.e. | |
| 272 | + // it is a local or anonymous class). The spec also states | |
| 273 | + // that if a class is anonymous then inner_name_index should | |
| 274 | + // be 0. | |
| 275 | + // | |
| 276 | + // Prior to jdk1.2, javac did not implement the spec. Instead | |
| 277 | + // it <em>always</em> set outer_class_info_index to the | |
| 278 | + // enclosing outer class and if the class was anonymous, | |
| 279 | + // it set inner_name_index to be the index of a CONSTANT_Utf8 | |
| 280 | + // entry containing the null string "" (idNull). This code is | |
| 281 | + // designed to handle either kind of class file. | |
| 282 | + // | |
| 283 | + // See also the compileClass() method in SourceClass.java. | |
| 284 | + | |
| 285 | + // Read in the inner_class_info | |
| 286 | + // InnerClasses_attribute.classes.inner_class_info_index | |
| 287 | + int inner_index = ds.readUnsignedShort(); | |
| 288 | + // could check for zero. | |
| 289 | + ClassDeclaration inner = cpool.getDeclaration(env, inner_index); | |
| 290 | + | |
| 291 | + // Read in the outer_class_info. Note that the index will be | |
| 292 | + // zero if the class is "not a member". | |
| 293 | + ClassDeclaration outer = null; | |
| 294 | + // InnerClasses_attribute.classes.outer_class_info_index | |
| 295 | + int outer_index = ds.readUnsignedShort(); | |
| 296 | + if (outer_index != 0) { | |
| 297 | + outer = cpool.getDeclaration(env, outer_index); | |
| 298 | + } | |
| 299 | + | |
| 300 | + // Read in the inner_name_index. This may be zero. An anonymous | |
| 301 | + // class will either have an inner_nm_index of zero (as the spec | |
| 302 | + // dictates) or it will have an inner_nm of idNull (for classes | |
| 303 | + // generated by pre-1.2 compilers). Handle both. | |
| 304 | + Identifier inner_nm = idNull; | |
| 305 | + // InnerClasses_attribute.classes.inner_name_index | |
| 306 | + int inner_nm_index = ds.readUnsignedShort(); | |
| 307 | + if (inner_nm_index != 0) { | |
| 308 | + inner_nm = Identifier.lookup(cpool.getString(inner_nm_index)); | |
| 309 | + } | |
| 310 | + | |
| 311 | + // Read in the modifiers for the inner class. | |
| 312 | + // InnerClasses_attribute.classes.inner_name_index | |
| 313 | + int mods = ds.readUnsignedShort(); | |
| 314 | + | |
| 315 | + // Is the class accessible? | |
| 316 | + // The old code checked for | |
| 317 | + // | |
| 318 | + // (!inner_nm.equals(idNull) && (mods & M_PRIVATE) == 0) | |
| 319 | + // | |
| 320 | + // which we will preserve to keep it working for class files | |
| 321 | + // generated by 1.1 compilers. In addition we check for | |
| 322 | + // | |
| 323 | + // (outer != null) | |
| 324 | + // | |
| 325 | + // as an additional check that only makes sense with 1.2 | |
| 326 | + // generated files. Note that it is entirely possible that | |
| 327 | + // the M_PRIVATE bit is always enough. We are being | |
| 328 | + // conservative here. | |
| 329 | + // | |
| 330 | + // The ATT_ALLCLASSES flag causes the M_PRIVATE modifier | |
| 331 | + // to be ignored, and is used by tools such as 'javap' that | |
| 332 | + // wish to examine all classes regardless of the normal access | |
| 333 | + // controls that apply during compilation. Note that anonymous | |
| 334 | + // and local classes are still not considered accessible, though | |
| 335 | + // named local classes in jdk1.1 may slip through. Note that | |
| 336 | + // this accessibility test is an optimization, and it is safe to | |
| 337 | + // err on the side of greater accessibility. | |
| 338 | + boolean accessible = | |
| 339 | + (outer != null) && | |
| 340 | + (!inner_nm.equals(idNull)) && | |
| 341 | + ((mods & M_PRIVATE) == 0 || | |
| 342 | + (flags & ATT_ALLCLASSES) != 0); | |
| 343 | + | |
| 344 | + // The reader should note that there has been a significant change | |
| 345 | + // in the way that the InnerClasses attribute is being handled. | |
| 346 | + // In particular, previously the compiler called initInner() for | |
| 347 | + // <em>every</em> inner class. Now the compiler does not call | |
| 348 | + // initInner() if the inner class is inaccessible. This means | |
| 349 | + // that inaccessible inner classes don't have any of the processing | |
| 350 | + // from initInner() done for them: fixing the access flags, | |
| 351 | + // setting outerClass, setting outerMember in their outerClass, | |
| 352 | + // etc. We believe this is fine: if the class is inaccessible | |
| 353 | + // and binary, then everyone who needs to see its internals | |
| 354 | + // has already been compiled. Hopefully. | |
| 355 | + | |
| 356 | + if (accessible) { | |
| 357 | + Identifier nm = | |
| 358 | + Identifier.lookupInner(outer.getName(), inner_nm); | |
| 359 | + | |
| 360 | + // Tell the type module about the nesting relation: | |
| 361 | + Type.tClass(nm); | |
| 362 | + | |
| 363 | + if (inner.equals(getClassDeclaration())) { | |
| 364 | + // The inner class in the record is this class. | |
| 365 | + try { | |
| 366 | + ClassDefinition outerClass = outer.getClassDefinition(env); | |
| 367 | + initInner(outerClass, mods); | |
| 368 | + } catch (ClassNotFound e) { | |
| 369 | + // report the error elsewhere | |
| 370 | + } | |
| 371 | + } else if (outer.equals(getClassDeclaration())) { | |
| 372 | + // The outer class in the record is this class. | |
| 373 | + try { | |
| 374 | + ClassDefinition innerClass = | |
| 375 | + inner.getClassDefinition(env); | |
| 376 | + initOuter(innerClass, mods); | |
| 377 | + } catch (ClassNotFound e) { | |
| 378 | + // report the error elsewhere | |
| 379 | + } | |
| 380 | + } | |
| 381 | + } | |
| 382 | + } | |
| 383 | + } | |
| 384 | + | |
| 385 | + private void initInner(ClassDefinition outerClass, int mods) { | |
| 386 | + if (getOuterClass() != null) | |
| 387 | + return; // already done | |
| 388 | + /****** | |
| 389 | + // Maybe set static, protected, or private. | |
| 390 | + if ((modifiers & M_PUBLIC) != 0) | |
| 391 | + mods &= M_STATIC; | |
| 392 | + else | |
| 393 | + mods &= M_PRIVATE | M_PROTECTED | M_STATIC; | |
| 394 | + modifiers |= mods; | |
| 395 | + ******/ | |
| 396 | + // For an inner class, the class access may have been weakened | |
| 397 | + // from that originally declared the source. We must take the | |
| 398 | + // actual access permissions against which we check any source | |
| 399 | + // we are currently compiling from the InnerClasses attribute. | |
| 400 | + // We attempt to guard here against bogus combinations of modifiers. | |
| 401 | + if ((mods & M_PRIVATE) != 0) { | |
| 402 | + // Private cannot be combined with public or protected. | |
| 403 | + mods &= ~(M_PUBLIC | M_PROTECTED); | |
| 404 | + } else if ((mods & M_PROTECTED) != 0) { | |
| 405 | + // Protected cannot be combined with public. | |
| 406 | + mods &= ~M_PUBLIC; | |
| 407 | + } | |
| 408 | + if ((mods & M_INTERFACE) != 0) { | |
| 409 | + // All interfaces are implicitly abstract. | |
| 410 | + // All interfaces that are members of a type are implicitly static. | |
| 411 | + mods |= (M_ABSTRACT | M_STATIC); | |
| 412 | + } | |
| 413 | + if (outerClass.isInterface()) { | |
| 414 | + // All types that are members of interfaces are implicitly | |
| 415 | + // public and static. | |
| 416 | + mods |= (M_PUBLIC | M_STATIC); | |
| 417 | + mods &= ~(M_PRIVATE | M_PROTECTED); | |
| 418 | + } | |
| 419 | + modifiers = mods; | |
| 420 | + | |
| 421 | + setOuterClass(outerClass); | |
| 422 | + | |
| 423 | + for (MemberDefinition field = getFirstMember(); | |
| 424 | + field != null; | |
| 425 | + field = field.getNextMember()) { | |
| 426 | + if (field.isUplevelValue() | |
| 427 | + && outerClass.getType().equals(field.getType()) | |
| 428 | + && field.getName().toString().startsWith(prefixThis)) { | |
| 429 | + setOuterMember(field); | |
| 430 | + } | |
| 431 | + } | |
| 432 | + } | |
| 433 | + | |
| 434 | + private void initOuter(ClassDefinition innerClass, int mods) { | |
| 435 | + if (innerClass instanceof BinaryClass) | |
| 436 | + ((BinaryClass)innerClass).initInner(this, mods); | |
| 437 | + addMember(new BinaryMember(innerClass)); | |
| 438 | + } | |
| 439 | + | |
| 440 | + /** | |
| 441 | + * Write the class out to a given stream. This function mirrors the loader. | |
| 442 | + */ | |
| 443 | + public void write(Environment env, OutputStream out) throws IOException { | |
| 444 | + DataOutputStream data = new DataOutputStream(out); | |
| 445 | + | |
| 446 | + // write out the header | |
| 447 | + data.writeInt(JAVA_MAGIC); | |
| 448 | + data.writeShort(env.getMinorVersion()); | |
| 449 | + data.writeShort(env.getMajorVersion()); | |
| 450 | + | |
| 451 | + // Write out the constant pool | |
| 452 | + cpool.write(data, env); | |
| 453 | + | |
| 454 | + // Write class information | |
| 455 | + data.writeShort(getModifiers() & ACCM_CLASS); | |
| 456 | + data.writeShort(cpool.indexObject(getClassDeclaration(), env)); | |
| 457 | + data.writeShort((getSuperClass() != null) | |
| 458 | + ? cpool.indexObject(getSuperClass(), env) : 0); | |
| 459 | + data.writeShort(interfaces.length); | |
| 460 | + for (int i = 0 ; i < interfaces.length ; i++) { | |
| 461 | + data.writeShort(cpool.indexObject(interfaces[i], env)); | |
| 462 | + } | |
| 463 | + | |
| 464 | + // count the fields and the methods | |
| 465 | + int fieldCount = 0, methodCount = 0; | |
| 466 | + for (MemberDefinition f = firstMember; f != null; f = f.getNextMember()) | |
| 467 | + if (f.isMethod()) methodCount++; else fieldCount++; | |
| 468 | + | |
| 469 | + // write out each the field count, and then each field | |
| 470 | + data.writeShort(fieldCount); | |
| 471 | + for (MemberDefinition f = firstMember; f != null; f = f.getNextMember()) { | |
| 472 | + if (!f.isMethod()) { | |
| 473 | + data.writeShort(f.getModifiers() & ACCM_FIELD); | |
| 474 | + String name = f.getName().toString(); | |
| 475 | + String signature = f.getType().getTypeSignature(); | |
| 476 | + data.writeShort(cpool.indexString(name, env)); | |
| 477 | + data.writeShort(cpool.indexString(signature, env)); | |
| 478 | + BinaryAttribute.write(((BinaryMember)f).atts, data, cpool, env); | |
| 479 | + } | |
| 480 | + } | |
| 481 | + | |
| 482 | + // write out each method count, and then each method | |
| 483 | + data.writeShort(methodCount); | |
| 484 | + for (MemberDefinition f = firstMember; f != null; f = f.getNextMember()) { | |
| 485 | + if (f.isMethod()) { | |
| 486 | + data.writeShort(f.getModifiers() & ACCM_METHOD); | |
| 487 | + String name = f.getName().toString(); | |
| 488 | + String signature = f.getType().getTypeSignature(); | |
| 489 | + data.writeShort(cpool.indexString(name, env)); | |
| 490 | + data.writeShort(cpool.indexString(signature, env)); | |
| 491 | + BinaryAttribute.write(((BinaryMember)f).atts, data, cpool, env); | |
| 492 | + } | |
| 493 | + } | |
| 494 | + | |
| 495 | + // write out the class attributes | |
| 496 | + BinaryAttribute.write(atts, data, cpool, env); | |
| 497 | + data.flush(); | |
| 498 | + } | |
| 499 | + | |
| 500 | + /** | |
| 501 | + * Get the dependencies | |
| 502 | + */ | |
| 503 | + public Enumeration getDependencies() { | |
| 504 | + return dependencies.elements(); | |
| 505 | + } | |
| 506 | + | |
| 507 | + /** | |
| 508 | + * Add a dependency | |
| 509 | + */ | |
| 510 | + public void addDependency(ClassDeclaration c) { | |
| 511 | + if ((c != null) && !dependencies.contains(c)) { | |
| 512 | + dependencies.addElement(c); | |
| 513 | + } | |
| 514 | + } | |
| 515 | + | |
| 516 | + /** | |
| 517 | + * Get the constant pool | |
| 518 | + */ | |
| 519 | + public BinaryConstantPool getConstants() { | |
| 520 | + return cpool; | |
| 521 | + } | |
| 522 | + | |
| 523 | + /** | |
| 524 | + * Get a class attribute | |
| 525 | + */ | |
| 526 | + public byte getAttribute(Identifier name)[] { | |
| 527 | + for (BinaryAttribute att = atts ; att != null ; att = att.next) { | |
| 528 | + if (att.name.equals(name)) { | |
| 529 | + return att.data; | |
| 530 | + } | |
| 531 | + } | |
| 532 | + return null; | |
| 533 | + } | |
| 534 | +} | |
| @@ -0,0 +1,111 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | + | |
| 27 | +package sun.tools.java; | |
| 28 | + | |
| 29 | +import java.io.*; | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * WARNING: The contents of this source file are not part of any | |
| 33 | + * supported API. Code that depends on them does so at its own risk: | |
| 34 | + * they are subject to change or removal without notice. | |
| 35 | + */ | |
| 36 | +public class BinaryCode implements Constants { | |
| 37 | + int maxStack; // maximum stack used by code | |
| 38 | + int maxLocals; // maximum locals used by code | |
| 39 | + BinaryExceptionHandler exceptionHandlers[]; | |
| 40 | + BinaryAttribute atts; // code attributes | |
| 41 | + BinaryConstantPool cpool; // constant pool of the class | |
| 42 | + byte code[]; // the byte code | |
| 43 | + | |
| 44 | + /** | |
| 45 | + * Construct the binary code from the code attribute | |
| 46 | + */ | |
| 47 | + | |
| 48 | + public | |
| 49 | + BinaryCode(byte data[], BinaryConstantPool cpool, Environment env) { | |
| 50 | + DataInputStream in = new DataInputStream(new ByteArrayInputStream(data)); | |
| 51 | + try { | |
| 52 | + this.cpool = cpool; | |
| 53 | + // JVM 4.7.4 CodeAttribute.max_stack | |
| 54 | + this.maxStack = in.readUnsignedShort(); | |
| 55 | + // JVM 4.7.4 CodeAttribute.max_locals | |
| 56 | + this.maxLocals = in.readUnsignedShort(); | |
| 57 | + // JVM 4.7.4 CodeAttribute.code_length | |
| 58 | + int code_length = in.readInt(); | |
| 59 | + this.code = new byte[code_length]; | |
| 60 | + // JVM 4.7.4 CodeAttribute.code[] | |
| 61 | + in.read(this.code); | |
| 62 | + // JVM 4.7.4 CodeAttribute.exception_table_length | |
| 63 | + int exception_count = in.readUnsignedShort(); | |
| 64 | + this.exceptionHandlers = new BinaryExceptionHandler[exception_count]; | |
| 65 | + for (int i = 0; i < exception_count; i++) { | |
| 66 | + // JVM 4.7.4 CodeAttribute.exception_table.start_pc | |
| 67 | + int start = in.readUnsignedShort(); | |
| 68 | + // JVM 4.7.4 CodeAttribute.exception_table.end_pc | |
| 69 | + int end = in.readUnsignedShort(); | |
| 70 | + // JVM 4.7.4 CodeAttribute.exception_table.handler_pc | |
| 71 | + int handler = in.readUnsignedShort(); | |
| 72 | + // JVM 4.7.4 CodeAttribute.exception_table.catch_type | |
| 73 | + ClassDeclaration xclass = cpool.getDeclaration(env, in.readUnsignedShort()); | |
| 74 | + this.exceptionHandlers[i] = | |
| 75 | + new BinaryExceptionHandler(start, end, handler, xclass); | |
| 76 | + } | |
| 77 | + this.atts = BinaryAttribute.load(in, cpool, ~0); | |
| 78 | + if (in.available() != 0) { | |
| 79 | + System.err.println("Should have exhausted input stream!"); | |
| 80 | + } | |
| 81 | + } catch (IOException e) { | |
| 82 | + throw new CompilerError(e); | |
| 83 | + } | |
| 84 | + } | |
| 85 | + | |
| 86 | + | |
| 87 | + /** | |
| 88 | + * Accessors | |
| 89 | + */ | |
| 90 | + | |
| 91 | + public BinaryExceptionHandler getExceptionHandlers()[] { | |
| 92 | + return exceptionHandlers; | |
| 93 | + } | |
| 94 | + | |
| 95 | + public byte getCode()[] { return code; } | |
| 96 | + | |
| 97 | + public int getMaxStack() { return maxStack; } | |
| 98 | + | |
| 99 | + public int getMaxLocals() { return maxLocals; } | |
| 100 | + | |
| 101 | + public BinaryAttribute getAttributes() { return atts; } | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * Load a binary class | |
| 105 | + */ | |
| 106 | + public static | |
| 107 | + BinaryCode load(BinaryMember bf, BinaryConstantPool cpool, Environment env) { | |
| 108 | + byte code[] = bf.getAttribute(idCode); | |
| 109 | + return (code != null) ? new BinaryCode(code, cpool, env) : null; | |
| 110 | + } | |
| 111 | +} | |
| @@ -0,0 +1,327 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +import java.io.IOException; | |
| 29 | +import java.io.DataInputStream; | |
| 30 | +import java.io.DataOutputStream; | |
| 31 | +import java.util.Vector; | |
| 32 | +import java.util.Hashtable; | |
| 33 | + | |
| 34 | +/** | |
| 35 | + * This class is used to represent a constant table once | |
| 36 | + * it is read from a class file. | |
| 37 | + * | |
| 38 | + * WARNING: The contents of this source file are not part of any | |
| 39 | + * supported API. Code that depends on them does so at its own risk: | |
| 40 | + * they are subject to change or removal without notice. | |
| 41 | + */ | |
| 42 | +public final | |
| 43 | +class BinaryConstantPool implements Constants { | |
| 44 | + private byte types[]; | |
| 45 | + private Object cpool[]; | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * Constructor | |
| 49 | + */ | |
| 50 | + BinaryConstantPool(DataInputStream in) throws IOException { | |
| 51 | + // JVM 4.1 ClassFile.constant_pool_count | |
| 52 | + types = new byte[in.readUnsignedShort()]; | |
| 53 | + cpool = new Object[types.length]; | |
| 54 | + for (int i = 1 ; i < cpool.length ; i++) { | |
| 55 | + int j = i; | |
| 56 | + // JVM 4.4 cp_info.tag | |
| 57 | + switch(types[i] = in.readByte()) { | |
| 58 | + case CONSTANT_UTF8: | |
| 59 | + cpool[i] = in.readUTF(); | |
| 60 | + break; | |
| 61 | + | |
| 62 | + case CONSTANT_INTEGER: | |
| 63 | + cpool[i] = new Integer(in.readInt()); | |
| 64 | + break; | |
| 65 | + case CONSTANT_FLOAT: | |
| 66 | + cpool[i] = new Float(in.readFloat()); | |
| 67 | + break; | |
| 68 | + case CONSTANT_LONG: | |
| 69 | + cpool[i++] = new Long(in.readLong()); | |
| 70 | + break; | |
| 71 | + case CONSTANT_DOUBLE: | |
| 72 | + cpool[i++] = new Double(in.readDouble()); | |
| 73 | + break; | |
| 74 | + | |
| 75 | + case CONSTANT_CLASS: | |
| 76 | + case CONSTANT_STRING: | |
| 77 | + // JVM 4.4.3 CONSTANT_String_info.string_index | |
| 78 | + // or JVM 4.4.1 CONSTANT_Class_info.name_index | |
| 79 | + cpool[i] = new Integer(in.readUnsignedShort()); | |
| 80 | + break; | |
| 81 | + | |
| 82 | + case CONSTANT_FIELD: | |
| 83 | + case CONSTANT_METHOD: | |
| 84 | + case CONSTANT_INTERFACEMETHOD: | |
| 85 | + case CONSTANT_NAMEANDTYPE: | |
| 86 | + // JVM 4.4.2 CONSTANT_*ref_info.class_index & name_and_type_index | |
| 87 | + cpool[i] = new Integer((in.readUnsignedShort() << 16) | in.readUnsignedShort()); | |
| 88 | + break; | |
| 89 | + | |
| 90 | + case 0: | |
| 91 | + default: | |
| 92 | + throw new ClassFormatError("invalid constant type: " + (int)types[i]); | |
| 93 | + } | |
| 94 | + } | |
| 95 | + } | |
| 96 | + | |
| 97 | + /** | |
| 98 | + * get a integer | |
| 99 | + */ | |
| 100 | + public int getInteger(int n) { | |
| 101 | + return (n == 0) ? 0 : ((Number)cpool[n]).intValue(); | |
| 102 | + } | |
| 103 | + | |
| 104 | + /** | |
| 105 | + * get a value | |
| 106 | + */ | |
| 107 | + public Object getValue(int n) { | |
| 108 | + return (n == 0) ? null : cpool[n]; | |
| 109 | + } | |
| 110 | + | |
| 111 | + /** | |
| 112 | + * get a string | |
| 113 | + */ | |
| 114 | + public String getString(int n) { | |
| 115 | + return (n == 0) ? null : (String)cpool[n]; | |
| 116 | + } | |
| 117 | + | |
| 118 | + /** | |
| 119 | + * get an identifier | |
| 120 | + */ | |
| 121 | + public Identifier getIdentifier(int n) { | |
| 122 | + return (n == 0) ? null : Identifier.lookup(getString(n)); | |
| 123 | + } | |
| 124 | + | |
| 125 | + /** | |
| 126 | + * get class declaration | |
| 127 | + */ | |
| 128 | + public ClassDeclaration getDeclarationFromName(Environment env, int n) { | |
| 129 | + return (n == 0) ? null : env.getClassDeclaration(Identifier.lookup(getString(n).replace('/','.'))); | |
| 130 | + } | |
| 131 | + | |
| 132 | + /** | |
| 133 | + * get class declaration | |
| 134 | + */ | |
| 135 | + public ClassDeclaration getDeclaration(Environment env, int n) { | |
| 136 | + return (n == 0) ? null : getDeclarationFromName(env, getInteger(n)); | |
| 137 | + } | |
| 138 | + | |
| 139 | + /** | |
| 140 | + * get a type from a type signature | |
| 141 | + */ | |
| 142 | + public Type getType(int n) { | |
| 143 | + return Type.tType(getString(n)); | |
| 144 | + } | |
| 145 | + | |
| 146 | + /** | |
| 147 | + * get the type of constant given an index | |
| 148 | + */ | |
| 149 | + public int getConstantType(int n) { | |
| 150 | + return types[n]; | |
| 151 | + } | |
| 152 | + | |
| 153 | + /** | |
| 154 | + * get the n-th constant from the constant pool | |
| 155 | + */ | |
| 156 | + public Object getConstant(int n, Environment env) { | |
| 157 | + int constant_type = getConstantType(n); | |
| 158 | + switch (constant_type) { | |
| 159 | + case CONSTANT_INTEGER: | |
| 160 | + case CONSTANT_FLOAT: | |
| 161 | + case CONSTANT_LONG: | |
| 162 | + case CONSTANT_DOUBLE: | |
| 163 | + return getValue(n); | |
| 164 | + | |
| 165 | + case CONSTANT_CLASS: | |
| 166 | + return getDeclaration(env, n); | |
| 167 | + | |
| 168 | + case CONSTANT_STRING: | |
| 169 | + return getString(getInteger(n)); | |
| 170 | + | |
| 171 | + case CONSTANT_FIELD: | |
| 172 | + case CONSTANT_METHOD: | |
| 173 | + case CONSTANT_INTERFACEMETHOD: | |
| 174 | + try { | |
| 175 | + int key = getInteger(n); | |
| 176 | + ClassDefinition clazz = | |
| 177 | + getDeclaration(env, key >> 16).getClassDefinition(env); | |
| 178 | + int name_and_type = getInteger(key & 0xFFFF); | |
| 179 | + Identifier id = getIdentifier(name_and_type >> 16); | |
| 180 | + Type type = getType(name_and_type & 0xFFFF); | |
| 181 | + | |
| 182 | + for (MemberDefinition field = clazz.getFirstMatch(id); | |
| 183 | + field != null; | |
| 184 | + field = field.getNextMatch()) { | |
| 185 | + Type field_type = field.getType(); | |
| 186 | + if ((constant_type == CONSTANT_FIELD) | |
| 187 | + ? (field_type == type) | |
| 188 | + : (field_type.equalArguments(type))) | |
| 189 | + return field; | |
| 190 | + } | |
| 191 | + } catch (ClassNotFound e) { | |
| 192 | + } | |
| 193 | + return null; | |
| 194 | + | |
| 195 | + default: | |
| 196 | + throw new ClassFormatError("invalid constant type: " + | |
| 197 | + constant_type); | |
| 198 | + } | |
| 199 | + } | |
| 200 | + | |
| 201 | + | |
| 202 | + /** | |
| 203 | + * Get a list of dependencies, ie: all the classes referenced in this | |
| 204 | + * constant pool. | |
| 205 | + */ | |
| 206 | + public Vector getDependencies(Environment env) { | |
| 207 | + Vector v = new Vector(); | |
| 208 | + for (int i = 1 ; i < cpool.length ; i++) { | |
| 209 | + switch(types[i]) { | |
| 210 | + case CONSTANT_CLASS: | |
| 211 | + v.addElement(getDeclarationFromName(env, getInteger(i))); | |
| 212 | + break; | |
| 213 | + } | |
| 214 | + } | |
| 215 | + return v; | |
| 216 | + } | |
| 217 | + | |
| 218 | + Hashtable indexHashObject, indexHashAscii; | |
| 219 | + Vector MoreStuff; | |
| 220 | + | |
| 221 | + /** | |
| 222 | + * Find the index of an Object in the constant pool | |
| 223 | + */ | |
| 224 | + public int indexObject(Object obj, Environment env) { | |
| 225 | + if (indexHashObject == null) | |
| 226 | + createIndexHash(env); | |
| 227 | + Integer result = (Integer)indexHashObject.get(obj); | |
| 228 | + if (result == null) | |
| 229 | + throw new IndexOutOfBoundsException("Cannot find object " + obj + " of type " + | |
| 230 | + obj.getClass() + " in constant pool"); | |
| 231 | + return result.intValue(); | |
| 232 | + } | |
| 233 | + | |
| 234 | + /** | |
| 235 | + * Find the index of an ascii string in the constant pool. If it's not in | |
| 236 | + * the constant pool, then add it at the end. | |
| 237 | + */ | |
| 238 | + public int indexString(String string, Environment env) { | |
| 239 | + if (indexHashObject == null) | |
| 240 | + createIndexHash(env); | |
| 241 | + Integer result = (Integer)indexHashAscii.get(string); | |
| 242 | + if (result == null) { | |
| 243 | + if (MoreStuff == null) MoreStuff = new Vector(); | |
| 244 | + result = new Integer(cpool.length + MoreStuff.size()); | |
| 245 | + MoreStuff.addElement(string); | |
| 246 | + indexHashAscii.put(string, result); | |
| 247 | + } | |
| 248 | + return result.intValue(); | |
| 249 | + } | |
| 250 | + | |
| 251 | + /** | |
| 252 | + * Create a hash table of all the items in the constant pool that could | |
| 253 | + * possibly be referenced from the outside. | |
| 254 | + */ | |
| 255 | + | |
| 256 | + public void createIndexHash(Environment env) { | |
| 257 | + indexHashObject = new Hashtable(); | |
| 258 | + indexHashAscii = new Hashtable(); | |
| 259 | + for (int i = 1; i < cpool.length; i++) { | |
| 260 | + if (types[i] == CONSTANT_UTF8) { | |
| 261 | + indexHashAscii.put(cpool[i], new Integer(i)); | |
| 262 | + } else { | |
| 263 | + try { | |
| 264 | + indexHashObject.put(getConstant(i, env), new Integer(i)); | |
| 265 | + } catch (ClassFormatError e) { } | |
| 266 | + } | |
| 267 | + } | |
| 268 | + } | |
| 269 | + | |
| 270 | + | |
| 271 | + /** | |
| 272 | + * Write out the contents of the constant pool, including any additions | |
| 273 | + * that have been added. | |
| 274 | + */ | |
| 275 | + public void write(DataOutputStream out, Environment env) throws IOException { | |
| 276 | + int length = cpool.length; | |
| 277 | + if (MoreStuff != null) | |
| 278 | + length += MoreStuff.size(); | |
| 279 | + out.writeShort(length); | |
| 280 | + for (int i = 1 ; i < cpool.length; i++) { | |
| 281 | + int type = types[i]; | |
| 282 | + Object x = cpool[i]; | |
| 283 | + out.writeByte(type); | |
| 284 | + switch (type) { | |
| 285 | + case CONSTANT_UTF8: | |
| 286 | + out.writeUTF((String) x); | |
| 287 | + break; | |
| 288 | + case CONSTANT_INTEGER: | |
| 289 | + out.writeInt(((Number)x).intValue()); | |
| 290 | + break; | |
| 291 | + case CONSTANT_FLOAT: | |
| 292 | + out.writeFloat(((Number)x).floatValue()); | |
| 293 | + break; | |
| 294 | + case CONSTANT_LONG: | |
| 295 | + out.writeLong(((Number)x).longValue()); | |
| 296 | + i++; | |
| 297 | + break; | |
| 298 | + case CONSTANT_DOUBLE: | |
| 299 | + out.writeDouble(((Number)x).doubleValue()); | |
| 300 | + i++; | |
| 301 | + break; | |
| 302 | + case CONSTANT_CLASS: | |
| 303 | + case CONSTANT_STRING: | |
| 304 | + out.writeShort(((Number)x).intValue()); | |
| 305 | + break; | |
| 306 | + case CONSTANT_FIELD: | |
| 307 | + case CONSTANT_METHOD: | |
| 308 | + case CONSTANT_INTERFACEMETHOD: | |
| 309 | + case CONSTANT_NAMEANDTYPE: { | |
| 310 | + int value = ((Number)x).intValue(); | |
| 311 | + out.writeShort(value >> 16); | |
| 312 | + out.writeShort(value & 0xFFFF); | |
| 313 | + break; | |
| 314 | + } | |
| 315 | + default: | |
| 316 | + throw new ClassFormatError("invalid constant type: " | |
| 317 | + + (int)types[i]); | |
| 318 | + } | |
| 319 | + } | |
| 320 | + for (int i = cpool.length; i < length; i++) { | |
| 321 | + String string = (String)(MoreStuff.elementAt(i - cpool.length)); | |
| 322 | + out.writeByte(CONSTANT_UTF8); | |
| 323 | + out.writeUTF(string); | |
| 324 | + } | |
| 325 | + } | |
| 326 | + | |
| 327 | +} | |
| @@ -0,0 +1,49 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * A single exception handler. This class hangs off BinaryCode. | |
| 30 | + * | |
| 31 | + * WARNING: The contents of this source file are not part of any | |
| 32 | + * supported API. Code that depends on them does so at its own risk: | |
| 33 | + * they are subject to change or removal without notice. | |
| 34 | + */ | |
| 35 | + | |
| 36 | +public class BinaryExceptionHandler { | |
| 37 | + public int startPC; | |
| 38 | + public int endPC; | |
| 39 | + public int handlerPC; | |
| 40 | + public ClassDeclaration exceptionClass; | |
| 41 | + | |
| 42 | + BinaryExceptionHandler(int start, int end, | |
| 43 | + int handler, ClassDeclaration xclass) { | |
| 44 | + startPC = start; | |
| 45 | + endPC = end; | |
| 46 | + handlerPC = handler; | |
| 47 | + exceptionClass = xclass; | |
| 48 | + } | |
| 49 | +} | |
| @@ -0,0 +1,260 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +import sun.tools.tree.*; | |
| 29 | +import java.util.Vector; | |
| 30 | +import java.util.Hashtable; | |
| 31 | +import java.io.IOException; | |
| 32 | +import java.io.DataInputStream; | |
| 33 | +import java.io.ByteArrayInputStream; | |
| 34 | + | |
| 35 | +/** | |
| 36 | + * This class represents a binary member | |
| 37 | + * | |
| 38 | + * WARNING: The contents of this source file are not part of any | |
| 39 | + * supported API. Code that depends on them does so at its own risk: | |
| 40 | + * they are subject to change or removal without notice. | |
| 41 | + */ | |
| 42 | +public final | |
| 43 | +class BinaryMember extends MemberDefinition { | |
| 44 | + Expression value; | |
| 45 | + BinaryAttribute atts; | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * Constructor | |
| 49 | + */ | |
| 50 | + public BinaryMember(ClassDefinition clazz, int modifiers, Type type, | |
| 51 | + Identifier name, BinaryAttribute atts) { | |
| 52 | + super(0, clazz, modifiers, type, name, null, null); | |
| 53 | + this.atts = atts; | |
| 54 | + | |
| 55 | + // Was it compiled as deprecated? | |
| 56 | + if (getAttribute(idDeprecated) != null) { | |
| 57 | + this.modifiers |= M_DEPRECATED; | |
| 58 | + } | |
| 59 | + | |
| 60 | + // Was it synthesized by the compiler? | |
| 61 | + if (getAttribute(idSynthetic) != null) { | |
| 62 | + this.modifiers |= M_SYNTHETIC; | |
| 63 | + } | |
| 64 | + } | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * Constructor for an inner class. | |
| 68 | + */ | |
| 69 | + public BinaryMember(ClassDefinition innerClass) { | |
| 70 | + super(innerClass); | |
| 71 | + } | |
| 72 | + | |
| 73 | + /** | |
| 74 | + * Inline allowed (currently only allowed for the constructor of Object). | |
| 75 | + */ | |
| 76 | + public boolean isInlineable(Environment env, boolean fromFinal) { | |
| 77 | + // It is possible for 'getSuperClass()' to return null due to error | |
| 78 | + // recovery from cyclic inheritace. Can this cause a problem here? | |
| 79 | + return isConstructor() && (getClassDefinition().getSuperClass() == null); | |
| 80 | + } | |
| 81 | + | |
| 82 | + /** | |
| 83 | + * Get arguments | |
| 84 | + */ | |
| 85 | + public Vector getArguments() { | |
| 86 | + if (isConstructor() && (getClassDefinition().getSuperClass() == null)) { | |
| 87 | + Vector v = new Vector(); | |
| 88 | + v.addElement(new LocalMember(0, getClassDefinition(), 0, | |
| 89 | + getClassDefinition().getType(), idThis)); | |
| 90 | + return v; | |
| 91 | + } | |
| 92 | + return null; | |
| 93 | + } | |
| 94 | + | |
| 95 | + /** | |
| 96 | + * Get exceptions | |
| 97 | + */ | |
| 98 | + public ClassDeclaration[] getExceptions(Environment env) { | |
| 99 | + if ((!isMethod()) || (exp != null)) { | |
| 100 | + return exp; | |
| 101 | + } | |
| 102 | + byte data[] = getAttribute(idExceptions); | |
| 103 | + if (data == null) { | |
| 104 | + return new ClassDeclaration[0]; | |
| 105 | + } | |
| 106 | + | |
| 107 | + try { | |
| 108 | + BinaryConstantPool cpool = ((BinaryClass)getClassDefinition()).getConstants(); | |
| 109 | + DataInputStream in = new DataInputStream(new ByteArrayInputStream(data)); | |
| 110 | + // JVM 4.7.5 Exceptions_attribute.number_of_exceptions | |
| 111 | + int n = in.readUnsignedShort(); | |
| 112 | + exp = new ClassDeclaration[n]; | |
| 113 | + for (int i = 0 ; i < n ; i++) { | |
| 114 | + // JVM 4.7.5 Exceptions_attribute.exception_index_table[] | |
| 115 | + exp[i] = cpool.getDeclaration(env, in.readUnsignedShort()); | |
| 116 | + } | |
| 117 | + return exp; | |
| 118 | + } catch (IOException e) { | |
| 119 | + throw new CompilerError(e); | |
| 120 | + } | |
| 121 | + } | |
| 122 | + | |
| 123 | + /** | |
| 124 | + * Get documentation | |
| 125 | + */ | |
| 126 | + public String getDocumentation() { | |
| 127 | + if (documentation != null) { | |
| 128 | + return documentation; | |
| 129 | + } | |
| 130 | + byte data[] = getAttribute(idDocumentation); | |
| 131 | + if (data == null) { | |
| 132 | + return null; | |
| 133 | + } | |
| 134 | + try { | |
| 135 | + return documentation = new DataInputStream(new ByteArrayInputStream(data)).readUTF(); | |
| 136 | + } catch (IOException e) { | |
| 137 | + throw new CompilerError(e); | |
| 138 | + } | |
| 139 | + } | |
| 140 | + | |
| 141 | + /** | |
| 142 | + * Check if constant: Will it inline away to a constant? | |
| 143 | + * This override is needed to solve bug 4128266. It is also | |
| 144 | + * integral to the solution of 4119776. | |
| 145 | + */ | |
| 146 | + private boolean isConstantCache = false; | |
| 147 | + private boolean isConstantCached = false; | |
| 148 | + public boolean isConstant() { | |
| 149 | + if (!isConstantCached) { | |
| 150 | + isConstantCache = isFinal() | |
| 151 | + && isVariable() | |
| 152 | + && getAttribute(idConstantValue) != null; | |
| 153 | + isConstantCached = true; | |
| 154 | + } | |
| 155 | + return isConstantCache; | |
| 156 | + } | |
| 157 | + | |
| 158 | + /** | |
| 159 | + * Get the value | |
| 160 | + */ | |
| 161 | + public Node getValue(Environment env) { | |
| 162 | + if (isMethod()) { | |
| 163 | + return null; | |
| 164 | + } | |
| 165 | + if (!isFinal()) { | |
| 166 | + return null; | |
| 167 | + } | |
| 168 | + if (getValue() != null) { | |
| 169 | + return (Expression)getValue(); | |
| 170 | + } | |
| 171 | + byte data[] = getAttribute(idConstantValue); | |
| 172 | + if (data == null) { | |
| 173 | + return null; | |
| 174 | + } | |
| 175 | + | |
| 176 | + try { | |
| 177 | + BinaryConstantPool cpool = ((BinaryClass)getClassDefinition()).getConstants(); | |
| 178 | + // JVM 4.7.3 ConstantValue.constantvalue_index | |
| 179 | + Object obj = cpool.getValue(new DataInputStream(new ByteArrayInputStream(data)).readUnsignedShort()); | |
| 180 | + switch (getType().getTypeCode()) { | |
| 181 | + case TC_BOOLEAN: | |
| 182 | + setValue(new BooleanExpression(0, ((Number)obj).intValue() != 0)); | |
| 183 | + break; | |
| 184 | + case TC_BYTE: | |
| 185 | + case TC_SHORT: | |
| 186 | + case TC_CHAR: | |
| 187 | + case TC_INT: | |
| 188 | + setValue(new IntExpression(0, ((Number)obj).intValue())); | |
| 189 | + break; | |
| 190 | + case TC_LONG: | |
| 191 | + setValue(new LongExpression(0, ((Number)obj).longValue())); | |
| 192 | + break; | |
| 193 | + case TC_FLOAT: | |
| 194 | + setValue(new FloatExpression(0, ((Number)obj).floatValue())); | |
| 195 | + break; | |
| 196 | + case TC_DOUBLE: | |
| 197 | + setValue(new DoubleExpression(0, ((Number)obj).doubleValue())); | |
| 198 | + break; | |
| 199 | + case TC_CLASS: | |
| 200 | + setValue(new StringExpression(0, (String)cpool.getValue(((Number)obj).intValue()))); | |
| 201 | + break; | |
| 202 | + } | |
| 203 | + return (Expression)getValue(); | |
| 204 | + } catch (IOException e) { | |
| 205 | + throw new CompilerError(e); | |
| 206 | + } | |
| 207 | + } | |
| 208 | + | |
| 209 | + /** | |
| 210 | + * Get a field attribute | |
| 211 | + */ | |
| 212 | + public byte[] getAttribute(Identifier name) { | |
| 213 | + for (BinaryAttribute att = atts ; att != null ; att = att.next) { | |
| 214 | + if (att.name.equals(name)) { | |
| 215 | + return att.data; | |
| 216 | + } | |
| 217 | + } | |
| 218 | + return null; | |
| 219 | + } | |
| 220 | + | |
| 221 | + public boolean deleteAttribute(Identifier name) { | |
| 222 | + BinaryAttribute walker = null, next = null; | |
| 223 | + | |
| 224 | + boolean succeed = false; | |
| 225 | + | |
| 226 | + while (atts.name.equals(name)) { | |
| 227 | + atts = atts.next; | |
| 228 | + succeed = true; | |
| 229 | + } | |
| 230 | + for (walker = atts; walker != null; walker = next) { | |
| 231 | + next = walker.next; | |
| 232 | + if (next != null) { | |
| 233 | + if (next.name.equals(name)) { | |
| 234 | + walker.next = next.next; | |
| 235 | + next = next.next; | |
| 236 | + succeed = true; | |
| 237 | + } | |
| 238 | + } | |
| 239 | + } | |
| 240 | + for (walker = atts; walker != null; walker = walker.next) { | |
| 241 | + if (walker.name.equals(name)) { | |
| 242 | + throw new InternalError("Found attribute " + name); | |
| 243 | + } | |
| 244 | + } | |
| 245 | + | |
| 246 | + return succeed; | |
| 247 | + } | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + /* | |
| 252 | + * Add an attribute to a field | |
| 253 | + */ | |
| 254 | + public void addAttribute(Identifier name, byte data[], Environment env) { | |
| 255 | + this.atts = new BinaryAttribute(name, data, this.atts); | |
| 256 | + // Make sure that the new attribute is in the constant pool | |
| 257 | + ((BinaryClass)(this.clazz)).cpool.indexString(name.toString(), env); | |
| 258 | + } | |
| 259 | + | |
| 260 | +} | |
| @@ -0,0 +1,265 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This class represents an Java class declaration. It refers | |
| 30 | + * to either a binary or source definition. | |
| 31 | + * | |
| 32 | + * ClassDefinitions are loaded on demand, this means that | |
| 33 | + * class declarations are late bound. The definition of the | |
| 34 | + * class is obtained in stages. The status field describes | |
| 35 | + * the state of the class definition: | |
| 36 | + * | |
| 37 | + * CS_UNDEFINED - the definition is not yet loaded | |
| 38 | + * CS_UNDECIDED - a binary definition is loaded, but it is | |
| 39 | + * still unclear if the source definition need to | |
| 40 | + * be loaded | |
| 41 | + * CS_BINARY - the binary class is loaded | |
| 42 | + * CS_PARSED - the class is loaded from the source file, the | |
| 43 | + * type information is available, but the class has | |
| 44 | + * not yet been compiled. | |
| 45 | + * CS_CHECKED - the class is loaded from the source file and has | |
| 46 | + * been type-checked. | |
| 47 | + * CS_COMPILED - the class has been type checked, compiled, | |
| 48 | + * and written out. | |
| 49 | + * CS_NOTFOUND - no class definition could be found | |
| 50 | + * | |
| 51 | + * WARNING: The contents of this source file are not part of any | |
| 52 | + * supported API. Code that depends on them does so at its own risk: | |
| 53 | + * they are subject to change or removal without notice. | |
| 54 | + */ | |
| 55 | + | |
| 56 | +public final | |
| 57 | +class ClassDeclaration implements Constants { | |
| 58 | + int status; | |
| 59 | + Type type; | |
| 60 | + ClassDefinition definition; | |
| 61 | + | |
| 62 | + /** | |
| 63 | + * Constructor | |
| 64 | + */ | |
| 65 | + public ClassDeclaration(Identifier name) { | |
| 66 | + this.type = Type.tClass(name); | |
| 67 | + } | |
| 68 | + | |
| 69 | + /** | |
| 70 | + * Get the status of the class | |
| 71 | + */ | |
| 72 | + public int getStatus() { | |
| 73 | + return status; | |
| 74 | + } | |
| 75 | + | |
| 76 | + /** | |
| 77 | + * Get the name of the class | |
| 78 | + */ | |
| 79 | + public Identifier getName() { | |
| 80 | + return type.getClassName(); | |
| 81 | + } | |
| 82 | + | |
| 83 | + /** | |
| 84 | + * Get the type of the class | |
| 85 | + */ | |
| 86 | + public Type getType() { | |
| 87 | + return type; | |
| 88 | + } | |
| 89 | + | |
| 90 | + /** | |
| 91 | + * Check if the class is defined | |
| 92 | + */ | |
| 93 | + public boolean isDefined() { | |
| 94 | + switch (status) { | |
| 95 | + case CS_BINARY: | |
| 96 | + case CS_PARSED: | |
| 97 | + case CS_CHECKED: | |
| 98 | + case CS_COMPILED: | |
| 99 | + return true; | |
| 100 | + } | |
| 101 | + return false; | |
| 102 | + } | |
| 103 | + | |
| 104 | + /** | |
| 105 | + * Get the definition of this class. Returns null if | |
| 106 | + * the class is not yet defined. | |
| 107 | + */ | |
| 108 | + public ClassDefinition getClassDefinition() { | |
| 109 | + return definition; | |
| 110 | + } | |
| 111 | + | |
| 112 | + /** | |
| 113 | + * This is a flag for use by getClassDefinition(env). It is | |
| 114 | + * used to mark that a class has been successfully looked up | |
| 115 | + * by that method before. | |
| 116 | + */ | |
| 117 | + private boolean found = false; | |
| 118 | + | |
| 119 | + /** | |
| 120 | + * Get the definition of this class, if the class is not | |
| 121 | + * yet defined, load the definition. Loading a class may | |
| 122 | + * throw various exceptions. | |
| 123 | + */ | |
| 124 | + public ClassDefinition getClassDefinition(Environment env) | |
| 125 | + throws ClassNotFound { | |
| 126 | + if (tracing) env.dtEvent("getClassDefinition: " + | |
| 127 | + getName() + ", status " + getStatus()); | |
| 128 | + | |
| 129 | + // The majority of calls to getClassDefinition() are duplicates. | |
| 130 | + // This check makes them fast. It also allows us to avoid | |
| 131 | + // duplicate, useless calls to basicCheck(). In the future it | |
| 132 | + // would be good to add an additional status value, CS_BASICCHECKED. | |
| 133 | + if (found) { | |
| 134 | + return definition; | |
| 135 | + } | |
| 136 | + | |
| 137 | + for(;;) { | |
| 138 | + switch (status) { | |
| 139 | + case CS_UNDEFINED: | |
| 140 | + case CS_UNDECIDED: | |
| 141 | + case CS_SOURCE: | |
| 142 | + env.loadDefinition(this); | |
| 143 | + break; | |
| 144 | + | |
| 145 | + case CS_BINARY: | |
| 146 | + case CS_PARSED: | |
| 147 | + //+FIX FOR BUGID 4056065 | |
| 148 | + //definition.basicCheck(env); | |
| 149 | + if (!definition.isInsideLocal()) { | |
| 150 | + // Classes inside a block, including anonymous classes, | |
| 151 | + // are checked when their surrounding member is checked. | |
| 152 | + definition.basicCheck(env); | |
| 153 | + } | |
| 154 | + //-FIX FOR BUGID 4056065 | |
| 155 | + found = true; | |
| 156 | + return definition; | |
| 157 | + | |
| 158 | + case CS_CHECKED: | |
| 159 | + case CS_COMPILED: | |
| 160 | + found = true; | |
| 161 | + return definition; | |
| 162 | + | |
| 163 | + default: | |
| 164 | + throw new ClassNotFound(getName()); | |
| 165 | + } | |
| 166 | + } | |
| 167 | + } | |
| 168 | + | |
| 169 | + /** | |
| 170 | + * Get the definition of this class, if the class is not | |
| 171 | + * yet defined, load the definition. Loading a class may | |
| 172 | + * throw various exceptions. Perform no basicCheck() on this | |
| 173 | + * class. | |
| 174 | + */ | |
| 175 | + public ClassDefinition getClassDefinitionNoCheck(Environment env) throws ClassNotFound { | |
| 176 | + if (tracing) env.dtEvent("getClassDefinition: " + | |
| 177 | + getName() + ", status " + getStatus()); | |
| 178 | + for(;;) { | |
| 179 | + switch (status) { | |
| 180 | + case CS_UNDEFINED: | |
| 181 | + case CS_UNDECIDED: | |
| 182 | + case CS_SOURCE: | |
| 183 | + env.loadDefinition(this); | |
| 184 | + break; | |
| 185 | + | |
| 186 | + case CS_BINARY: | |
| 187 | + case CS_PARSED: | |
| 188 | + case CS_CHECKED: | |
| 189 | + case CS_COMPILED: | |
| 190 | + return definition; | |
| 191 | + | |
| 192 | + default: | |
| 193 | + throw new ClassNotFound(getName()); | |
| 194 | + } | |
| 195 | + } | |
| 196 | + } | |
| 197 | + | |
| 198 | + /** | |
| 199 | + * Set the class definition | |
| 200 | + */ | |
| 201 | + public void setDefinition(ClassDefinition definition, int status) { | |
| 202 | + | |
| 203 | + // Sanity checks. | |
| 204 | + | |
| 205 | + // The name of the definition should match that of the declaration. | |
| 206 | + if ((definition != null) && !getName().equals(definition.getName())) { | |
| 207 | + throw new CompilerError("setDefinition: name mismatch: " + | |
| 208 | + this + ", " + definition); | |
| 209 | + } | |
| 210 | + | |
| 211 | + // The status states can be considered ordered in the same | |
| 212 | + // manner as their numerical values. We expect classes to | |
| 213 | + // progress through a sequence of monotonically increasing | |
| 214 | + // states. NOTE: There are currently exceptions to this rule | |
| 215 | + // which are believed to be legitimate. In particular, a | |
| 216 | + // class may be checked more than once, though we believe that | |
| 217 | + // this is unnecessary and may be avoided. | |
| 218 | + /*-----------------* | |
| 219 | + if (status <= this.status) { | |
| 220 | + System.out.println("STATUS REGRESSION: " + | |
| 221 | + this + " FROM " + this.status + " TO " + status); | |
| 222 | + } | |
| 223 | + *------------------*/ | |
| 224 | + | |
| 225 | + this.definition = definition; | |
| 226 | + this.status = status; | |
| 227 | + } | |
| 228 | + | |
| 229 | + /** | |
| 230 | + * Equality | |
| 231 | + */ | |
| 232 | + public boolean equals(Object obj) { | |
| 233 | + if ((obj != null) && (obj instanceof ClassDeclaration)) { | |
| 234 | + return type.equals(((ClassDeclaration)obj).type); | |
| 235 | + } | |
| 236 | + return false; | |
| 237 | + } | |
| 238 | + | |
| 239 | + /** | |
| 240 | + * toString | |
| 241 | + */ | |
| 242 | + public String toString() { | |
| 243 | + String name = getName().toString(); | |
| 244 | + String type = "type "; | |
| 245 | + String nested = getName().isInner() ? "nested " : ""; | |
| 246 | + if (getClassDefinition() != null) { | |
| 247 | + if (getClassDefinition().isInterface()) { | |
| 248 | + type = "interface "; | |
| 249 | + } else { | |
| 250 | + type = "class "; | |
| 251 | + } | |
| 252 | + if (!getClassDefinition().isTopLevel()) { | |
| 253 | + nested = "inner "; | |
| 254 | + if (getClassDefinition().isLocal()) { | |
| 255 | + nested = "local "; | |
| 256 | + if (!getClassDefinition().isAnonymous()) { | |
| 257 | + name = getClassDefinition().getLocalName() + | |
| 258 | + " (" + name + ")"; | |
| 259 | + } | |
| 260 | + } | |
| 261 | + } | |
| 262 | + } | |
| 263 | + return nested + type + name; | |
| 264 | + } | |
| 265 | +} | |
| @@ -0,0 +1,2085 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +import java.util.*; | |
| 29 | +import java.io.OutputStream; | |
| 30 | +import java.io.PrintStream; | |
| 31 | +import sun.tools.tree.Context; | |
| 32 | +import sun.tools.tree.Vset; | |
| 33 | +import sun.tools.tree.Expression; | |
| 34 | +import sun.tools.tree.LocalMember; | |
| 35 | +import sun.tools.tree.UplevelReference; | |
| 36 | + | |
| 37 | +/** | |
| 38 | + * This class is a Java class definition | |
| 39 | + * | |
| 40 | + * WARNING: The contents of this source file are not part of any | |
| 41 | + * supported API. Code that depends on them does so at its own risk: | |
| 42 | + * they are subject to change or removal without notice. | |
| 43 | + */ | |
| 44 | +public | |
| 45 | +class ClassDefinition implements Constants { | |
| 46 | + | |
| 47 | + protected Object source; | |
| 48 | + protected long where; | |
| 49 | + protected int modifiers; | |
| 50 | + protected Identifier localName; // for local classes | |
| 51 | + protected ClassDeclaration declaration; | |
| 52 | + protected IdentifierToken superClassId; | |
| 53 | + protected IdentifierToken interfaceIds[]; | |
| 54 | + protected ClassDeclaration superClass; | |
| 55 | + protected ClassDeclaration interfaces[]; | |
| 56 | + protected ClassDefinition outerClass; | |
| 57 | + protected MemberDefinition outerMember; | |
| 58 | + protected MemberDefinition innerClassMember; // field for me in outerClass | |
| 59 | + protected MemberDefinition firstMember; | |
| 60 | + protected MemberDefinition lastMember; | |
| 61 | + protected boolean resolved; | |
| 62 | + protected String documentation; | |
| 63 | + protected boolean error; | |
| 64 | + protected boolean nestError; | |
| 65 | + protected UplevelReference references; | |
| 66 | + protected boolean referencesFrozen; | |
| 67 | + private Hashtable fieldHash = new Hashtable(31); | |
| 68 | + private int abstr; | |
| 69 | + | |
| 70 | + // Table of local and anonymous classes whose internal names are constructed | |
| 71 | + // using the current class as a prefix. This is part of a fix for | |
| 72 | + // bugid 4054523 and 4030421. See also 'Environment.getClassDefinition' | |
| 73 | + // and 'BatchEnvironment.makeClassDefinition'. Allocated on demand. | |
| 74 | + private Hashtable localClasses = null; | |
| 75 | + private final int LOCAL_CLASSES_SIZE = 31; | |
| 76 | + | |
| 77 | + // The immediately surrounding context in which the class appears. | |
| 78 | + // Set at the beginning of checking, upon entry to 'SourceClass.checkInternal'. | |
| 79 | + // Null for classes that are not local or inside a local class. | |
| 80 | + // At present, this field exists only for the benefit of 'resolveName' as part | |
| 81 | + // of the fix for 4095716. | |
| 82 | + protected Context classContext; | |
| 83 | + | |
| 84 | + // The saved class context is now also used in 'SourceClass.getAccessMember'. | |
| 85 | + // Provide read-only access via this method. Part of fix for 4098093. | |
| 86 | + public Context getClassContext() { | |
| 87 | + return classContext; | |
| 88 | + } | |
| 89 | + | |
| 90 | + | |
| 91 | + /** | |
| 92 | + * Constructor | |
| 93 | + */ | |
| 94 | + protected ClassDefinition(Object source, long where, ClassDeclaration declaration, | |
| 95 | + int modifiers, IdentifierToken superClass, IdentifierToken interfaces[]) { | |
| 96 | + this.source = source; | |
| 97 | + this.where = where; | |
| 98 | + this.declaration = declaration; | |
| 99 | + this.modifiers = modifiers; | |
| 100 | + this.superClassId = superClass; | |
| 101 | + this.interfaceIds = interfaces; | |
| 102 | + } | |
| 103 | + | |
| 104 | + /** | |
| 105 | + * Get the source of the class | |
| 106 | + */ | |
| 107 | + public final Object getSource() { | |
| 108 | + return source; | |
| 109 | + } | |
| 110 | + | |
| 111 | + /** | |
| 112 | + * Check if there were any errors in this class. | |
| 113 | + */ | |
| 114 | + public final boolean getError() { | |
| 115 | + return error; | |
| 116 | + } | |
| 117 | + | |
| 118 | + /** | |
| 119 | + * Mark this class to be erroneous. | |
| 120 | + */ | |
| 121 | + public final void setError() { | |
| 122 | + this.error = true; | |
| 123 | + setNestError(); | |
| 124 | + } | |
| 125 | + | |
| 126 | + /** | |
| 127 | + * Check if there were any errors in our class nest. | |
| 128 | + */ | |
| 129 | + public final boolean getNestError() { | |
| 130 | + // Check to see if our error value is set, or if any of our | |
| 131 | + // outer classes' error values are set. This will work in | |
| 132 | + // conjunction with setError(), which sets the error value | |
| 133 | + // of its outer class, to yield true is any of our nest | |
| 134 | + // siblings has an error. This addresses bug 4111488: either | |
| 135 | + // code should be generated for all classes in a nest, or | |
| 136 | + // none of them. | |
| 137 | + return nestError || ((outerClass != null) ? outerClass.getNestError() : false); | |
| 138 | + } | |
| 139 | + | |
| 140 | + /** | |
| 141 | + * Mark this class, and all siblings in its class nest, to be | |
| 142 | + * erroneous. | |
| 143 | + */ | |
| 144 | + public final void setNestError() { | |
| 145 | + this.nestError = true; | |
| 146 | + if (outerClass != null) { | |
| 147 | + // If we have an outer class, set it to be erroneous as well. | |
| 148 | + // This will work in conjunction with getError(), which checks | |
| 149 | + // the error value of its outer class, to set the whole class | |
| 150 | + // nest to be erroneous. This address bug 4111488: either | |
| 151 | + // code should be generated for all classes in a nest, or | |
| 152 | + // none of them. | |
| 153 | + outerClass.setNestError(); | |
| 154 | + } | |
| 155 | + } | |
| 156 | + | |
| 157 | + /** | |
| 158 | + * Get the position in the input | |
| 159 | + */ | |
| 160 | + public final long getWhere() { | |
| 161 | + return where; | |
| 162 | + } | |
| 163 | + | |
| 164 | + /** | |
| 165 | + * Get the class declaration | |
| 166 | + */ | |
| 167 | + public final ClassDeclaration getClassDeclaration() { | |
| 168 | + return declaration; | |
| 169 | + } | |
| 170 | + | |
| 171 | + /** | |
| 172 | + * Get the class' modifiers | |
| 173 | + */ | |
| 174 | + public final int getModifiers() { | |
| 175 | + return modifiers; | |
| 176 | + } | |
| 177 | + public final void subModifiers(int mod) { | |
| 178 | + modifiers &= ~mod; | |
| 179 | + } | |
| 180 | + public final void addModifiers(int mod) { | |
| 181 | + modifiers |= mod; | |
| 182 | + } | |
| 183 | + | |
| 184 | + // *** DEBUG *** | |
| 185 | + protected boolean supersCheckStarted = !(this instanceof sun.tools.javac.SourceClass); | |
| 186 | + | |
| 187 | + /** | |
| 188 | + * Get the class' super class | |
| 189 | + */ | |
| 190 | + public final ClassDeclaration getSuperClass() { | |
| 191 | + /*--- | |
| 192 | + if (superClass == null && superClassId != null) | |
| 193 | + throw new CompilerError("getSuperClass "+superClassId); | |
| 194 | + // There are obscure cases where null is the right answer, | |
| 195 | + // in order to enable some error reporting later on. | |
| 196 | + // For example: class T extends T.N { class N { } } | |
| 197 | + ---*/ | |
| 198 | + | |
| 199 | + // *** DEBUG *** | |
| 200 | + // This method should not be called if the superclass has not been resolved. | |
| 201 | + if (!supersCheckStarted) throw new CompilerError("unresolved super"); | |
| 202 | + | |
| 203 | + return superClass; | |
| 204 | + } | |
| 205 | + | |
| 206 | + /** | |
| 207 | + * Get the super class, and resolve names now if necessary. | |
| 208 | + * | |
| 209 | + * It is only possible to resolve names at this point if we are | |
| 210 | + * a source class. The provision of this method at this level | |
| 211 | + * in the class hierarchy is dubious, but see 'getInnerClass' below. | |
| 212 | + * All other calls to 'getSuperClass(env)' appear in 'SourceClass'. | |
| 213 | + * NOTE: An older definition of this method has been moved to | |
| 214 | + * 'SourceClass', where it overrides this one. | |
| 215 | + * | |
| 216 | + * @see #resolveTypeStructure | |
| 217 | + */ | |
| 218 | + | |
| 219 | + public ClassDeclaration getSuperClass(Environment env) { | |
| 220 | + return getSuperClass(); | |
| 221 | + } | |
| 222 | + | |
| 223 | + /** | |
| 224 | + * Get the class' interfaces | |
| 225 | + */ | |
| 226 | + public final ClassDeclaration getInterfaces()[] { | |
| 227 | + if (interfaces == null) throw new CompilerError("getInterfaces"); | |
| 228 | + return interfaces; | |
| 229 | + } | |
| 230 | + | |
| 231 | + /** | |
| 232 | + * Get the class' enclosing class (or null if not inner) | |
| 233 | + */ | |
| 234 | + public final ClassDefinition getOuterClass() { | |
| 235 | + return outerClass; | |
| 236 | + } | |
| 237 | + | |
| 238 | + /** | |
| 239 | + * Set the class' enclosing class. Must be done at most once. | |
| 240 | + */ | |
| 241 | + protected final void setOuterClass(ClassDefinition outerClass) { | |
| 242 | + if (this.outerClass != null) throw new CompilerError("setOuterClass"); | |
| 243 | + this.outerClass = outerClass; | |
| 244 | + } | |
| 245 | + | |
| 246 | + /** | |
| 247 | + * Set the class' enclosing current instance pointer. | |
| 248 | + * Must be done at most once. | |
| 249 | + */ | |
| 250 | + protected final void setOuterMember(MemberDefinition outerMember) { | |
| 251 | + | |
| 252 | + if (isStatic() || !isInnerClass()) throw new CompilerError("setOuterField"); | |
| 253 | + if (this.outerMember != null) throw new CompilerError("setOuterField"); | |
| 254 | + this.outerMember = outerMember; | |
| 255 | + } | |
| 256 | + | |
| 257 | + /** | |
| 258 | + * Tell if the class is inner. | |
| 259 | + * This predicate also returns true for top-level nested types. | |
| 260 | + * To test for a true inner class as seen by the programmer, | |
| 261 | + * use <tt>!isTopLevel()</tt>. | |
| 262 | + */ | |
| 263 | + public final boolean isInnerClass() { | |
| 264 | + return outerClass != null; | |
| 265 | + } | |
| 266 | + | |
| 267 | + /** | |
| 268 | + * Tell if the class is a member of another class. | |
| 269 | + * This is false for package members and for block-local classes. | |
| 270 | + */ | |
| 271 | + public final boolean isMember() { | |
| 272 | + return outerClass != null && !isLocal(); | |
| 273 | + } | |
| 274 | + | |
| 275 | + /** | |
| 276 | + * Tell if the class is "top-level", which is either a package member, | |
| 277 | + * or a static member of another top-level class. | |
| 278 | + */ | |
| 279 | + public final boolean isTopLevel() { | |
| 280 | + return outerClass == null || isStatic() || isInterface(); | |
| 281 | + } | |
| 282 | + | |
| 283 | + /** | |
| 284 | + * Tell if the class is local or inside a local class, | |
| 285 | + * which means it cannot be mentioned outside of its file. | |
| 286 | + */ | |
| 287 | + | |
| 288 | + // The comment above is true only because M_LOCAL is set | |
| 289 | + // whenever M_ANONYMOUS is. I think it is risky to assume that | |
| 290 | + // isAnonymous(x) => isLocal(x). | |
| 291 | + | |
| 292 | + public final boolean isInsideLocal() { | |
| 293 | + return isLocal() || | |
| 294 | + (outerClass != null && outerClass.isInsideLocal()); | |
| 295 | + } | |
| 296 | + | |
| 297 | + /** | |
| 298 | + * Tell if the class is local or or anonymous class, or inside | |
| 299 | + * such a class, which means it cannot be mentioned outside of | |
| 300 | + * its file. | |
| 301 | + */ | |
| 302 | + public final boolean isInsideLocalOrAnonymous() { | |
| 303 | + return isLocal() || isAnonymous () || | |
| 304 | + (outerClass != null && outerClass.isInsideLocalOrAnonymous()); | |
| 305 | + } | |
| 306 | + | |
| 307 | + /** | |
| 308 | + * Return a simple identifier for this class (idNull if anonymous). | |
| 309 | + */ | |
| 310 | + public Identifier getLocalName() { | |
| 311 | + if (localName != null) { | |
| 312 | + return localName; | |
| 313 | + } | |
| 314 | + // This is also the name of the innerClassMember, if any: | |
| 315 | + return getName().getFlatName().getName(); | |
| 316 | + } | |
| 317 | + | |
| 318 | + /** | |
| 319 | + * Set the local name of a class. Must be a local class. | |
| 320 | + */ | |
| 321 | + public void setLocalName(Identifier name) { | |
| 322 | + if (isLocal()) { | |
| 323 | + localName = name; | |
| 324 | + } | |
| 325 | + } | |
| 326 | + | |
| 327 | + /** | |
| 328 | + * If inner, get the field for this class in the enclosing class | |
| 329 | + */ | |
| 330 | + public final MemberDefinition getInnerClassMember() { | |
| 331 | + if (outerClass == null) | |
| 332 | + return null; | |
| 333 | + if (innerClassMember == null) { | |
| 334 | + // We must find the field in the outer class. | |
| 335 | + Identifier nm = getName().getFlatName().getName(); | |
| 336 | + for (MemberDefinition field = outerClass.getFirstMatch(nm); | |
| 337 | + field != null; field = field.getNextMatch()) { | |
| 338 | + if (field.isInnerClass()) { | |
| 339 | + innerClassMember = field; | |
| 340 | + break; | |
| 341 | + } | |
| 342 | + } | |
| 343 | + if (innerClassMember == null) | |
| 344 | + throw new CompilerError("getInnerClassField"); | |
| 345 | + } | |
| 346 | + return innerClassMember; | |
| 347 | + } | |
| 348 | + | |
| 349 | + /** | |
| 350 | + * If inner, return an innermost uplevel self pointer, if any exists. | |
| 351 | + * Otherwise, return null. | |
| 352 | + */ | |
| 353 | + public final MemberDefinition findOuterMember() { | |
| 354 | + return outerMember; | |
| 355 | + } | |
| 356 | + | |
| 357 | + /** | |
| 358 | + * See if this is a (nested) static class. | |
| 359 | + */ | |
| 360 | + public final boolean isStatic() { | |
| 361 | + return (modifiers & ACC_STATIC) != 0; | |
| 362 | + } | |
| 363 | + | |
| 364 | + /** | |
| 365 | + * Get the class' top-level enclosing class | |
| 366 | + */ | |
| 367 | + public final ClassDefinition getTopClass() { | |
| 368 | + ClassDefinition p, q; | |
| 369 | + for (p = this; (q = p.outerClass) != null; p = q) | |
| 370 | + ; | |
| 371 | + return p; | |
| 372 | + } | |
| 373 | + | |
| 374 | + /** | |
| 375 | + * Get the class' first field or first match | |
| 376 | + */ | |
| 377 | + public final MemberDefinition getFirstMember() { | |
| 378 | + return firstMember; | |
| 379 | + } | |
| 380 | + public final MemberDefinition getFirstMatch(Identifier name) { | |
| 381 | + return (MemberDefinition)fieldHash.get(name); | |
| 382 | + } | |
| 383 | + | |
| 384 | + /** | |
| 385 | + * Get the class' name | |
| 386 | + */ | |
| 387 | + public final Identifier getName() { | |
| 388 | + return declaration.getName(); | |
| 389 | + } | |
| 390 | + | |
| 391 | + /** | |
| 392 | + * Get the class' type | |
| 393 | + */ | |
| 394 | + public final Type getType() { | |
| 395 | + return declaration.getType(); | |
| 396 | + } | |
| 397 | + | |
| 398 | + /** | |
| 399 | + * Get the class' documentation | |
| 400 | + */ | |
| 401 | + public String getDocumentation() { | |
| 402 | + return documentation; | |
| 403 | + } | |
| 404 | + | |
| 405 | + /** | |
| 406 | + * Return true if the given documentation string contains a deprecation | |
| 407 | + * paragraph. This is true if the string contains the tag @deprecated | |
| 408 | + * is the first word in a line. | |
| 409 | + */ | |
| 410 | + public static boolean containsDeprecated(String documentation) { | |
| 411 | + if (documentation == null) { | |
| 412 | + return false; | |
| 413 | + } | |
| 414 | + doScan: | |
| 415 | + for (int scan = 0; | |
| 416 | + (scan = documentation.indexOf(paraDeprecated, scan)) >= 0; | |
| 417 | + scan += paraDeprecated.length()) { | |
| 418 | + // make sure there is only whitespace between this word | |
| 419 | + // and the beginning of the line | |
| 420 | + for (int beg = scan-1; beg >= 0; beg--) { | |
| 421 | + char ch = documentation.charAt(beg); | |
| 422 | + if (ch == '\n' || ch == '\r') { | |
| 423 | + break; // OK | |
| 424 | + } | |
| 425 | + if (!Character.isSpace(ch)) { | |
| 426 | + continue doScan; | |
| 427 | + } | |
| 428 | + } | |
| 429 | + // make sure the char after the word is space or end of line | |
| 430 | + int end = scan+paraDeprecated.length(); | |
| 431 | + if (end < documentation.length()) { | |
| 432 | + char ch = documentation.charAt(end); | |
| 433 | + if (!(ch == '\n' || ch == '\r') && !Character.isSpace(ch)) { | |
| 434 | + continue doScan; | |
| 435 | + } | |
| 436 | + } | |
| 437 | + return true; | |
| 438 | + } | |
| 439 | + return false; | |
| 440 | + } | |
| 441 | + | |
| 442 | + public final boolean inSamePackage(ClassDeclaration c) { | |
| 443 | + // find out if the class stored in c is defined in the same | |
| 444 | + // package as the current class. | |
| 445 | + return inSamePackage(c.getName().getQualifier()); | |
| 446 | + } | |
| 447 | + | |
| 448 | + public final boolean inSamePackage(ClassDefinition c) { | |
| 449 | + // find out if the class stored in c is defined in the same | |
| 450 | + // package as the current class. | |
| 451 | + return inSamePackage(c.getName().getQualifier()); | |
| 452 | + } | |
| 453 | + | |
| 454 | + public final boolean inSamePackage(Identifier packageName) { | |
| 455 | + return (getName().getQualifier().equals(packageName)); | |
| 456 | + } | |
| 457 | + | |
| 458 | + /** | |
| 459 | + * Checks | |
| 460 | + */ | |
| 461 | + public final boolean isInterface() { | |
| 462 | + return (getModifiers() & M_INTERFACE) != 0; | |
| 463 | + } | |
| 464 | + public final boolean isClass() { | |
| 465 | + return (getModifiers() & M_INTERFACE) == 0; | |
| 466 | + } | |
| 467 | + public final boolean isPublic() { | |
| 468 | + return (getModifiers() & M_PUBLIC) != 0; | |
| 469 | + } | |
| 470 | + public final boolean isPrivate() { | |
| 471 | + return (getModifiers() & M_PRIVATE) != 0; | |
| 472 | + } | |
| 473 | + public final boolean isProtected() { | |
| 474 | + return (getModifiers() & M_PROTECTED) != 0; | |
| 475 | + } | |
| 476 | + public final boolean isPackagePrivate() { | |
| 477 | + return (modifiers & (M_PUBLIC | M_PRIVATE | M_PROTECTED)) == 0; | |
| 478 | + } | |
| 479 | + public final boolean isFinal() { | |
| 480 | + return (getModifiers() & M_FINAL) != 0; | |
| 481 | + } | |
| 482 | + public final boolean isAbstract() { | |
| 483 | + return (getModifiers() & M_ABSTRACT) != 0; | |
| 484 | + } | |
| 485 | + public final boolean isSynthetic() { | |
| 486 | + return (getModifiers() & M_SYNTHETIC) != 0; | |
| 487 | + } | |
| 488 | + public final boolean isDeprecated() { | |
| 489 | + return (getModifiers() & M_DEPRECATED) != 0; | |
| 490 | + } | |
| 491 | + public final boolean isAnonymous() { | |
| 492 | + return (getModifiers() & M_ANONYMOUS) != 0; | |
| 493 | + } | |
| 494 | + public final boolean isLocal() { | |
| 495 | + return (getModifiers() & M_LOCAL) != 0; | |
| 496 | + } | |
| 497 | + public final boolean hasConstructor() { | |
| 498 | + return getFirstMatch(idInit) != null; | |
| 499 | + } | |
| 500 | + | |
| 501 | + | |
| 502 | + /** | |
| 503 | + * Check to see if a class must be abstract. This method replaces | |
| 504 | + * isAbstract(env) | |
| 505 | + */ | |
| 506 | + public final boolean mustBeAbstract(Environment env) { | |
| 507 | + // If it is declared abstract, return true. | |
| 508 | + // (Fix for 4110534.) | |
| 509 | + if (isAbstract()) { | |
| 510 | + return true; | |
| 511 | + } | |
| 512 | + | |
| 513 | + // Check to see if the class should have been declared to be | |
| 514 | + // abstract. | |
| 515 | + | |
| 516 | + // We make sure that the inherited method collection has been | |
| 517 | + // performed. | |
| 518 | + collectInheritedMethods(env); | |
| 519 | + | |
| 520 | + // We check for any abstract methods inherited or declared | |
| 521 | + // by this class. | |
| 522 | + Iterator methods = getMethods(); | |
| 523 | + while (methods.hasNext()) { | |
| 524 | + MemberDefinition method = (MemberDefinition) methods.next(); | |
| 525 | + | |
| 526 | + if (method.isAbstract()) { | |
| 527 | + return true; | |
| 528 | + } | |
| 529 | + } | |
| 530 | + | |
| 531 | + // We check for hidden "permanently abstract" methods in | |
| 532 | + // our superclasses. | |
| 533 | + return getPermanentlyAbstractMethods().hasNext(); | |
| 534 | + } | |
| 535 | + | |
| 536 | + /** | |
| 537 | + * Check if this is a super class of another class | |
| 538 | + */ | |
| 539 | + public boolean superClassOf(Environment env, ClassDeclaration otherClass) | |
| 540 | + throws ClassNotFound { | |
| 541 | + while (otherClass != null) { | |
| 542 | + if (getClassDeclaration().equals(otherClass)) { | |
| 543 | + return true; | |
| 544 | + } | |
| 545 | + otherClass = otherClass.getClassDefinition(env).getSuperClass(); | |
| 546 | + } | |
| 547 | + return false; | |
| 548 | + } | |
| 549 | + | |
| 550 | + /** | |
| 551 | + * Check if this is an enclosing class of another class | |
| 552 | + */ | |
| 553 | + public boolean enclosingClassOf(ClassDefinition otherClass) { | |
| 554 | + while ((otherClass = otherClass.getOuterClass()) != null) { | |
| 555 | + if (this == otherClass) { | |
| 556 | + return true; | |
| 557 | + } | |
| 558 | + } | |
| 559 | + return false; | |
| 560 | + } | |
| 561 | + | |
| 562 | + /** | |
| 563 | + * Check if this is a sub class of another class | |
| 564 | + */ | |
| 565 | + public boolean subClassOf(Environment env, ClassDeclaration otherClass) throws ClassNotFound { | |
| 566 | + ClassDeclaration c = getClassDeclaration(); | |
| 567 | + while (c != null) { | |
| 568 | + if (c.equals(otherClass)) { | |
| 569 | + return true; | |
| 570 | + } | |
| 571 | + c = c.getClassDefinition(env).getSuperClass(); | |
| 572 | + } | |
| 573 | + return false; | |
| 574 | + } | |
| 575 | + | |
| 576 | + /** | |
| 577 | + * Check if this class is implemented by another class | |
| 578 | + */ | |
| 579 | + public boolean implementedBy(Environment env, ClassDeclaration c) throws ClassNotFound { | |
| 580 | + for (; c != null ; c = c.getClassDefinition(env).getSuperClass()) { | |
| 581 | + if (getClassDeclaration().equals(c)) { | |
| 582 | + return true; | |
| 583 | + } | |
| 584 | + ClassDeclaration intf[] = c.getClassDefinition(env).getInterfaces(); | |
| 585 | + for (int i = 0 ; i < intf.length ; i++) { | |
| 586 | + if (implementedBy(env, intf[i])) { | |
| 587 | + return true; | |
| 588 | + } | |
| 589 | + } | |
| 590 | + } | |
| 591 | + return false; | |
| 592 | + } | |
| 593 | + | |
| 594 | + /** | |
| 595 | + * Check to see if a class which implements interface `this' could | |
| 596 | + * possibly implement the interface `intDef'. Note that the only | |
| 597 | + * way that this can fail is if `this' and `intDef' have methods | |
| 598 | + * which are of the same signature and different return types. This | |
| 599 | + * method is used by Environment.explicitCast() to determine if a | |
| 600 | + * cast between two interfaces is legal. | |
| 601 | + * | |
| 602 | + * This method should only be called on a class after it has been | |
| 603 | + * basicCheck()'ed. | |
| 604 | + */ | |
| 605 | + public boolean couldImplement(ClassDefinition intDef) { | |
| 606 | + // Check to see if we could have done the necessary checks. | |
| 607 | + if (!doInheritanceChecks) { | |
| 608 | + throw new CompilerError("couldImplement: no checks"); | |
| 609 | + } | |
| 610 | + | |
| 611 | + // This method should only be called for interfaces. | |
| 612 | + if (!isInterface() || !intDef.isInterface()) { | |
| 613 | + throw new CompilerError("couldImplement: not interface"); | |
| 614 | + } | |
| 615 | + | |
| 616 | + // Make sure we are not called before we have collected our | |
| 617 | + // inheritance information. | |
| 618 | + if (allMethods == null) { | |
| 619 | + throw new CompilerError("couldImplement: called early"); | |
| 620 | + } | |
| 621 | + | |
| 622 | + // Get the other classes' methods. getMethods() in | |
| 623 | + // general can return methods which are not visible to the | |
| 624 | + // current package. We need to make sure that these do not | |
| 625 | + // prevent this class from being implemented. | |
| 626 | + Iterator otherMethods = intDef.getMethods(); | |
| 627 | + | |
| 628 | + while (otherMethods.hasNext()) { | |
| 629 | + // Get one of the methods from intDef... | |
| 630 | + MemberDefinition method = | |
| 631 | + (MemberDefinition) otherMethods.next(); | |
| 632 | + | |
| 633 | + Identifier name = method.getName(); | |
| 634 | + Type type = method.getType(); | |
| 635 | + | |
| 636 | + // See if we implement a method of the same signature... | |
| 637 | + MemberDefinition myMethod = allMethods.lookupSig(name, type); | |
| 638 | + | |
| 639 | + //System.out.println("Comparing\n\t" + myMethod + | |
| 640 | + // "\nand\n\t" + method); | |
| 641 | + | |
| 642 | + if (myMethod != null) { | |
| 643 | + // We do. Make sure the methods have the same return type. | |
| 644 | + if (!myMethod.sameReturnType(method)) { | |
| 645 | + return false; | |
| 646 | + } | |
| 647 | + } | |
| 648 | + } | |
| 649 | + | |
| 650 | + return true; | |
| 651 | + } | |
| 652 | + | |
| 653 | + /** | |
| 654 | + * Check if another class can be accessed from the 'extends' or 'implements' | |
| 655 | + * clause of this class. | |
| 656 | + */ | |
| 657 | + public boolean extendsCanAccess(Environment env, ClassDeclaration c) throws ClassNotFound { | |
| 658 | + | |
| 659 | + // Names in the 'extends' or 'implements' clause of an inner class | |
| 660 | + // are checked as if they appeared in the body of the surrounding class. | |
| 661 | + if (outerClass != null) { | |
| 662 | + return outerClass.canAccess(env, c); | |
| 663 | + } | |
| 664 | + | |
| 665 | + // We are a package member. | |
| 666 | + | |
| 667 | + ClassDefinition cdef = c.getClassDefinition(env); | |
| 668 | + | |
| 669 | + if (cdef.isLocal()) { | |
| 670 | + // No locals should be in scope in the 'extends' or | |
| 671 | + // 'implements' clause of a package member. | |
| 672 | + throw new CompilerError("top local"); | |
| 673 | + } | |
| 674 | + | |
| 675 | + if (cdef.isInnerClass()) { | |
| 676 | + MemberDefinition f = cdef.getInnerClassMember(); | |
| 677 | + | |
| 678 | + // Access to public member is always allowed. | |
| 679 | + if (f.isPublic()) { | |
| 680 | + return true; | |
| 681 | + } | |
| 682 | + | |
| 683 | + // Private access is ok only from the same class nest. This can | |
| 684 | + // happen only if the class represented by 'this' encloses the inner | |
| 685 | + // class represented by 'f'. | |
| 686 | + if (f.isPrivate()) { | |
| 687 | + return getClassDeclaration().equals(f.getTopClass().getClassDeclaration()); | |
| 688 | + } | |
| 689 | + | |
| 690 | + // Protected or default access -- allow access if in same package. | |
| 691 | + return getName().getQualifier().equals(f.getClassDeclaration().getName().getQualifier()); | |
| 692 | + } | |
| 693 | + | |
| 694 | + // Access to public member is always allowed. | |
| 695 | + if (cdef.isPublic()) { | |
| 696 | + return true; | |
| 697 | + } | |
| 698 | + | |
| 699 | + // Default access -- allow access if in same package. | |
| 700 | + return getName().getQualifier().equals(c.getName().getQualifier()); | |
| 701 | + } | |
| 702 | + | |
| 703 | + /** | |
| 704 | + * Check if another class can be accessed from within the body of this class. | |
| 705 | + */ | |
| 706 | + public boolean canAccess(Environment env, ClassDeclaration c) throws ClassNotFound { | |
| 707 | + ClassDefinition cdef = c.getClassDefinition(env); | |
| 708 | + | |
| 709 | + if (cdef.isLocal()) { | |
| 710 | + // if it's in scope, it's accessible | |
| 711 | + return true; | |
| 712 | + } | |
| 713 | + | |
| 714 | + if (cdef.isInnerClass()) { | |
| 715 | + return canAccess(env, cdef.getInnerClassMember()); | |
| 716 | + } | |
| 717 | + | |
| 718 | + // Public access is always ok | |
| 719 | + if (cdef.isPublic()) { | |
| 720 | + return true; | |
| 721 | + } | |
| 722 | + | |
| 723 | + // It must be in the same package | |
| 724 | + return getName().getQualifier().equals(c.getName().getQualifier()); | |
| 725 | + } | |
| 726 | + | |
| 727 | + /** | |
| 728 | + * Check if a field can be accessed from a class | |
| 729 | + */ | |
| 730 | + | |
| 731 | + public boolean canAccess(Environment env, MemberDefinition f) | |
| 732 | + throws ClassNotFound { | |
| 733 | + | |
| 734 | + // Public access is always ok | |
| 735 | + if (f.isPublic()) { | |
| 736 | + return true; | |
| 737 | + } | |
| 738 | + // Protected access is ok from a subclass | |
| 739 | + if (f.isProtected() && subClassOf(env, f.getClassDeclaration())) { | |
| 740 | + return true; | |
| 741 | + } | |
| 742 | + // Private access is ok only from the same class nest | |
| 743 | + if (f.isPrivate()) { | |
| 744 | + return getTopClass().getClassDeclaration() | |
| 745 | + .equals(f.getTopClass().getClassDeclaration()); | |
| 746 | + } | |
| 747 | + // It must be in the same package | |
| 748 | + return getName().getQualifier().equals(f.getClassDeclaration().getName().getQualifier()); | |
| 749 | + } | |
| 750 | + | |
| 751 | + /** | |
| 752 | + * Check if a class is entitled to inline access to a class from | |
| 753 | + * another class. | |
| 754 | + */ | |
| 755 | + public boolean permitInlinedAccess(Environment env, ClassDeclaration c) | |
| 756 | + throws ClassNotFound { | |
| 757 | + | |
| 758 | + return (env.opt() && c.equals(declaration)) || | |
| 759 | + (env.opt_interclass() && canAccess(env, c)); | |
| 760 | + } | |
| 761 | + | |
| 762 | + /** | |
| 763 | + * Check if a class is entitled to inline access to a method from | |
| 764 | + * another class. | |
| 765 | + */ | |
| 766 | + public boolean permitInlinedAccess(Environment env, MemberDefinition f) | |
| 767 | + throws ClassNotFound { | |
| 768 | + return (env.opt() | |
| 769 | + && (f.clazz.getClassDeclaration().equals(declaration))) || | |
| 770 | + (env.opt_interclass() && canAccess(env, f)); | |
| 771 | + } | |
| 772 | + | |
| 773 | + /** | |
| 774 | + * We know the the field is marked protected (and not public) and that | |
| 775 | + * the field is visible (as per canAccess). Can we access the field as | |
| 776 | + * <accessor>.<field>, where <accessor> has the type <accessorType>? | |
| 777 | + * | |
| 778 | + * Protected fields can only be accessed when the accessorType is a | |
| 779 | + * subclass of the current class | |
| 780 | + */ | |
| 781 | + public boolean protectedAccess(Environment env, MemberDefinition f, | |
| 782 | + Type accessorType) | |
| 783 | + throws ClassNotFound | |
| 784 | + { | |
| 785 | + | |
| 786 | + return | |
| 787 | + // static protected fields are accessible | |
| 788 | + f.isStatic() | |
| 789 | + || // allow array.clone() | |
| 790 | + (accessorType.isType(TC_ARRAY) && (f.getName() == idClone) | |
| 791 | + && (f.getType().getArgumentTypes().length == 0)) | |
| 792 | + || // <accessorType> is a subtype of the current class | |
| 793 | + (accessorType.isType(TC_CLASS) | |
| 794 | + && env.getClassDefinition(accessorType.getClassName()) | |
| 795 | + .subClassOf(env, getClassDeclaration())) | |
| 796 | + || // we are accessing the field from a friendly class (same package) | |
| 797 | + (getName().getQualifier() | |
| 798 | + .equals(f.getClassDeclaration().getName().getQualifier())); | |
| 799 | + } | |
| 800 | + | |
| 801 | + | |
| 802 | + /** | |
| 803 | + * Find or create an access method for a private member, | |
| 804 | + * or return null if this is not possible. | |
| 805 | + */ | |
| 806 | + public MemberDefinition getAccessMember(Environment env, Context ctx, | |
| 807 | + MemberDefinition field, boolean isSuper) { | |
| 808 | + throw new CompilerError("binary getAccessMember"); | |
| 809 | + } | |
| 810 | + | |
| 811 | + /** | |
| 812 | + * Find or create an update method for a private member, | |
| 813 | + * or return null if this is not possible. | |
| 814 | + */ | |
| 815 | + public MemberDefinition getUpdateMember(Environment env, Context ctx, | |
| 816 | + MemberDefinition field, boolean isSuper) { | |
| 817 | + throw new CompilerError("binary getUpdateMember"); | |
| 818 | + } | |
| 819 | + | |
| 820 | + /** | |
| 821 | + * Get a field from this class. Report ambiguous fields. | |
| 822 | + * If no accessible field is found, this method may return an | |
| 823 | + * inaccessible field to allow a useful error message. | |
| 824 | + * | |
| 825 | + * getVariable now takes the source class `source' as an argument. | |
| 826 | + * This allows getVariable to check whether a field is inaccessible | |
| 827 | + * before it signals that a field is ambiguous. The compiler used to | |
| 828 | + * signal an ambiguity even when one of the fields involved was not | |
| 829 | + * accessible. (bug 4053724) | |
| 830 | + */ | |
| 831 | + public MemberDefinition getVariable(Environment env, | |
| 832 | + Identifier nm, | |
| 833 | + ClassDefinition source) | |
| 834 | + throws AmbiguousMember, ClassNotFound { | |
| 835 | + | |
| 836 | + return getVariable0(env, nm, source, true, true); | |
| 837 | + } | |
| 838 | + | |
| 839 | + /* | |
| 840 | + * private fields are never inherited. package-private fields are | |
| 841 | + * not inherited across package boundaries. To capture this, we | |
| 842 | + * take two booleans as parameters: showPrivate indicates whether | |
| 843 | + * we have passed a class boundary, and showPackage indicates whether | |
| 844 | + * we have crossed a package boundary. | |
| 845 | + */ | |
| 846 | + private MemberDefinition getVariable0(Environment env, | |
| 847 | + Identifier nm, | |
| 848 | + ClassDefinition source, | |
| 849 | + boolean showPrivate, | |
| 850 | + boolean showPackage) | |
| 851 | + throws AmbiguousMember, ClassNotFound { | |
| 852 | + | |
| 853 | + // Check to see if this field is defined in the current class | |
| 854 | + for (MemberDefinition member = getFirstMatch(nm); | |
| 855 | + member != null; | |
| 856 | + member = member.getNextMatch()) { | |
| 857 | + if (member.isVariable()) { | |
| 858 | + if ((showPrivate || !member.isPrivate()) && | |
| 859 | + (showPackage || !member.isPackagePrivate())) { | |
| 860 | + // It is defined in this class. | |
| 861 | + return member; | |
| 862 | + } else { | |
| 863 | + // Even though this definition is not inherited, | |
| 864 | + // it hides all definitions in supertypes. | |
| 865 | + return null; | |
| 866 | + } | |
| 867 | + } | |
| 868 | + } | |
| 869 | + | |
| 870 | + // Find the field in our superclass. | |
| 871 | + ClassDeclaration sup = getSuperClass(); | |
| 872 | + MemberDefinition field = null; | |
| 873 | + if (sup != null) { | |
| 874 | + field = | |
| 875 | + sup.getClassDefinition(env) | |
| 876 | + .getVariable0(env, nm, source, | |
| 877 | + false, | |
| 878 | + showPackage && inSamePackage(sup)); | |
| 879 | + } | |
| 880 | + | |
| 881 | + // Find the field in our superinterfaces. | |
| 882 | + for (int i = 0 ; i < interfaces.length ; i++) { | |
| 883 | + // Try to look up the field in an interface. Since interfaces | |
| 884 | + // only have public fields, the values of the two boolean | |
| 885 | + // arguments are not important. | |
| 886 | + MemberDefinition field2 = | |
| 887 | + interfaces[i].getClassDefinition(env) | |
| 888 | + .getVariable0(env, nm, source, true, true); | |
| 889 | + | |
| 890 | + if (field2 != null) { | |
| 891 | + // If we have two different, accessible fields, then | |
| 892 | + // we've found an ambiguity. | |
| 893 | + if (field != null && | |
| 894 | + source.canAccess(env, field) && | |
| 895 | + field2 != field) { | |
| 896 | + | |
| 897 | + throw new AmbiguousMember(field2, field); | |
| 898 | + } | |
| 899 | + field = field2; | |
| 900 | + } | |
| 901 | + } | |
| 902 | + return field; | |
| 903 | + } | |
| 904 | + | |
| 905 | + /** | |
| 906 | + * Tells whether to report a deprecation error for this class. | |
| 907 | + */ | |
| 908 | + public boolean reportDeprecated(Environment env) { | |
| 909 | + return (isDeprecated() | |
| 910 | + || (outerClass != null && outerClass.reportDeprecated(env))); | |
| 911 | + } | |
| 912 | + | |
| 913 | + /** | |
| 914 | + * Note that this class is being used somehow by <tt>ref</tt>. | |
| 915 | + * Report deprecation errors, etc. | |
| 916 | + */ | |
| 917 | + public void noteUsedBy(ClassDefinition ref, long where, Environment env) { | |
| 918 | + // (Have this deal with canAccess() checks, too?) | |
| 919 | + if (reportDeprecated(env)) { | |
| 920 | + env.error(where, "warn.class.is.deprecated", this); | |
| 921 | + } | |
| 922 | + } | |
| 923 | + | |
| 924 | + /** | |
| 925 | + * Get an inner class. | |
| 926 | + * Look in supers but not outers. | |
| 927 | + * (This is used directly to resolve expressions like "site.K", and | |
| 928 | + * inside a loop to resolve lone names like "K" or the "K" in "K.L".) | |
| 929 | + * | |
| 930 | + * Called from 'Context' and 'FieldExpression' as well as this class. | |
| 931 | + * | |
| 932 | + * @see FieldExpression.checkCommon | |
| 933 | + * @see resolveName | |
| 934 | + */ | |
| 935 | + public MemberDefinition getInnerClass(Environment env, Identifier nm) | |
| 936 | + throws ClassNotFound { | |
| 937 | + // Note: AmbiguousClass will not be thrown unless and until | |
| 938 | + // inner classes can be defined inside interfaces. | |
| 939 | + | |
| 940 | + // Check if it is defined in the current class | |
| 941 | + for (MemberDefinition field = getFirstMatch(nm); | |
| 942 | + field != null ; field = field.getNextMatch()) { | |
| 943 | + if (field.isInnerClass()) { | |
| 944 | + if (field.getInnerClass().isLocal()) { | |
| 945 | + continue; // ignore this name; it is internally generated | |
| 946 | + } | |
| 947 | + return field; | |
| 948 | + } | |
| 949 | + } | |
| 950 | + | |
| 951 | + // Get it from the super class | |
| 952 | + // It is likely that 'getSuperClass()' could be made to work here | |
| 953 | + // but we would have to assure somehow that 'resolveTypeStructure' | |
| 954 | + // has been called on the current class nest. Since we can get | |
| 955 | + // here from 'resolveName', which is called from 'resolveSupers', | |
| 956 | + // it is possible that the first attempt to resolve the superclass | |
| 957 | + // will originate here, instead of in the call to 'getSuperClass' | |
| 958 | + // in 'checkSupers'. See 'resolveTypeStructure', in which a call | |
| 959 | + // to 'resolveSupers' precedes the call to 'checkSupers'. Why is | |
| 960 | + // name resolution done twice, first in 'resolveName'? | |
| 961 | + // NOTE: 'SourceMember.resolveTypeStructure' may initiate type | |
| 962 | + // structure resolution for an inner class. Normally, this | |
| 963 | + // occurs during the resolution of the outer class, but fields | |
| 964 | + // added after the resolution of their containing class will | |
| 965 | + // be resolved late -- see 'addMember(env,field)' below. | |
| 966 | + // This should only happen for synthetic members, which should | |
| 967 | + // never be an inner class. | |
| 968 | + ClassDeclaration sup = getSuperClass(env); | |
| 969 | + if (sup != null) | |
| 970 | + return sup.getClassDefinition(env).getInnerClass(env, nm); | |
| 971 | + | |
| 972 | + return null; | |
| 973 | + } | |
| 974 | + | |
| 975 | + /** | |
| 976 | + * Lookup a method. This code implements the method lookup | |
| 977 | + * mechanism specified in JLS 15.11.2. | |
| 978 | + * | |
| 979 | + * This mechanism cannot be used to lookup synthetic methods. | |
| 980 | + */ | |
| 981 | + private MemberDefinition matchMethod(Environment env, | |
| 982 | + ClassDefinition accessor, | |
| 983 | + Identifier methodName, | |
| 984 | + Type[] argumentTypes, | |
| 985 | + boolean isAnonConstCall, | |
| 986 | + Identifier accessPackage) | |
| 987 | + throws AmbiguousMember, ClassNotFound { | |
| 988 | + | |
| 989 | + if (allMethods == null || !allMethods.isFrozen()) { | |
| 990 | + // This may be too restrictive. | |
| 991 | + throw new CompilerError("matchMethod called early"); | |
| 992 | + // collectInheritedMethods(env); | |
| 993 | + } | |
| 994 | + | |
| 995 | + // A tentative maximally specific method. | |
| 996 | + MemberDefinition tentative = null; | |
| 997 | + | |
| 998 | + // A list of other methods which may be maximally specific too. | |
| 999 | + List candidateList = null; | |
| 1000 | + | |
| 1001 | + // Get all the methods inherited by this class which | |
| 1002 | + // have the name `methodName'. | |
| 1003 | + Iterator methods = allMethods.lookupName(methodName); | |
| 1004 | + | |
| 1005 | + while (methods.hasNext()) { | |
| 1006 | + MemberDefinition method = (MemberDefinition)methods.next(); | |
| 1007 | + | |
| 1008 | + // See if this method is applicable. | |
| 1009 | + if (!env.isApplicable(method, argumentTypes)) { | |
| 1010 | + continue; | |
| 1011 | + } | |
| 1012 | + | |
| 1013 | + // See if this method is accessible. | |
| 1014 | + if (accessor != null) { | |
| 1015 | + if (!accessor.canAccess(env, method)) { | |
| 1016 | + continue; | |
| 1017 | + } | |
| 1018 | + } else if (isAnonConstCall) { | |
| 1019 | + if (method.isPrivate() || | |
| 1020 | + (method.isPackagePrivate() && | |
| 1021 | + accessPackage != null && | |
| 1022 | + !inSamePackage(accessPackage))) { | |
| 1023 | + // For anonymous constructor accesses, we | |
| 1024 | + // haven't yet built an accessing class. | |
| 1025 | + // We disallow anonymous classes from seeing | |
| 1026 | + // private/package-private inaccessible | |
| 1027 | + // constructors in their superclass. | |
| 1028 | + continue; | |
| 1029 | + } | |
| 1030 | + } else { | |
| 1031 | + // If accessor is null, we assume that the access | |
| 1032 | + // is allowed. Query: is this option used? | |
| 1033 | + } | |
| 1034 | + | |
| 1035 | + if (tentative == null) { | |
| 1036 | + // `method' becomes our tentative maximally specific match. | |
| 1037 | + tentative = method; | |
| 1038 | + } else { | |
| 1039 | + if (env.isMoreSpecific(method, tentative)) { | |
| 1040 | + // We have found a method which is a strictly better | |
| 1041 | + // match than `tentative'. Replace it. | |
| 1042 | + tentative = method; | |
| 1043 | + } else { | |
| 1044 | + // If this method could possibly be another | |
| 1045 | + // maximally specific method, add it to our | |
| 1046 | + // list of other candidates. | |
| 1047 | + if (!env.isMoreSpecific(tentative,method)) { | |
| 1048 | + if (candidateList == null) { | |
| 1049 | + candidateList = new ArrayList(); | |
| 1050 | + } | |
| 1051 | + candidateList.add(method); | |
| 1052 | + } | |
| 1053 | + } | |
| 1054 | + } | |
| 1055 | + } | |
| 1056 | + | |
| 1057 | + if (tentative != null && candidateList != null) { | |
| 1058 | + // Find out if our `tentative' match is a uniquely | |
| 1059 | + // maximally specific. | |
| 1060 | + Iterator candidates = candidateList.iterator(); | |
| 1061 | + while (candidates.hasNext()) { | |
| 1062 | + MemberDefinition method = (MemberDefinition)candidates.next(); | |
| 1063 | + if (!env.isMoreSpecific(tentative, method)) { | |
| 1064 | + throw new AmbiguousMember(tentative, method); | |
| 1065 | + } | |
| 1066 | + } | |
| 1067 | + } | |
| 1068 | + | |
| 1069 | + return tentative; | |
| 1070 | + } | |
| 1071 | + | |
| 1072 | + /** | |
| 1073 | + * Lookup a method. This code implements the method lookup | |
| 1074 | + * mechanism specified in JLS 15.11.2. | |
| 1075 | + * | |
| 1076 | + * This mechanism cannot be used to lookup synthetic methods. | |
| 1077 | + */ | |
| 1078 | + public MemberDefinition matchMethod(Environment env, | |
| 1079 | + ClassDefinition accessor, | |
| 1080 | + Identifier methodName, | |
| 1081 | + Type[] argumentTypes) | |
| 1082 | + throws AmbiguousMember, ClassNotFound { | |
| 1083 | + | |
| 1084 | + return matchMethod(env, accessor, methodName, | |
| 1085 | + argumentTypes, false, null); | |
| 1086 | + } | |
| 1087 | + | |
| 1088 | + /** | |
| 1089 | + * Lookup a method. This code implements the method lookup | |
| 1090 | + * mechanism specified in JLS 15.11.2. | |
| 1091 | + * | |
| 1092 | + * This mechanism cannot be used to lookup synthetic methods. | |
| 1093 | + */ | |
| 1094 | + public MemberDefinition matchMethod(Environment env, | |
| 1095 | + ClassDefinition accessor, | |
| 1096 | + Identifier methodName) | |
| 1097 | + throws AmbiguousMember, ClassNotFound { | |
| 1098 | + | |
| 1099 | + return matchMethod(env, accessor, methodName, | |
| 1100 | + Type.noArgs, false, null); | |
| 1101 | + } | |
| 1102 | + | |
| 1103 | + /** | |
| 1104 | + * A version of matchMethod to be used only for constructors | |
| 1105 | + * when we cannot pass in a sourceClass argument. We just assert | |
| 1106 | + * our package name. | |
| 1107 | + * | |
| 1108 | + * This is used only for anonymous classes, where we have to look up | |
| 1109 | + * a (potentially) protected constructor with no valid sourceClass | |
| 1110 | + * parameter available. | |
| 1111 | + */ | |
| 1112 | + public MemberDefinition matchAnonConstructor(Environment env, | |
| 1113 | + Identifier accessPackage, | |
| 1114 | + Type argumentTypes[]) | |
| 1115 | + throws AmbiguousMember, ClassNotFound { | |
| 1116 | + | |
| 1117 | + return matchMethod(env, null, idInit, argumentTypes, | |
| 1118 | + true, accessPackage); | |
| 1119 | + } | |
| 1120 | + | |
| 1121 | + /** | |
| 1122 | + * Find a method, ie: exact match in this class or any of the super | |
| 1123 | + * classes. | |
| 1124 | + * | |
| 1125 | + * Only called by javadoc. For now I am holding off rewriting this | |
| 1126 | + * code to rely on collectInheritedMethods(), as that code has | |
| 1127 | + * not gotten along with javadoc in the past. | |
| 1128 | + */ | |
| 1129 | + public MemberDefinition findMethod(Environment env, Identifier nm, Type t) | |
| 1130 | + throws ClassNotFound { | |
| 1131 | + // look in the current class | |
| 1132 | + MemberDefinition f; | |
| 1133 | + for (f = getFirstMatch(nm) ; f != null ; f = f.getNextMatch()) { | |
| 1134 | + // Note that non-method types return false for equalArguments(). | |
| 1135 | + if (f.getType().equalArguments(t)) { | |
| 1136 | + return f; | |
| 1137 | + } | |
| 1138 | + } | |
| 1139 | + | |
| 1140 | + // constructors are not inherited | |
| 1141 | + if (nm.equals(idInit)) { | |
| 1142 | + return null; | |
| 1143 | + } | |
| 1144 | + | |
| 1145 | + // look in the super class | |
| 1146 | + ClassDeclaration sup = getSuperClass(); | |
| 1147 | + if (sup == null) | |
| 1148 | + return null; | |
| 1149 | + | |
| 1150 | + return sup.getClassDefinition(env).findMethod(env, nm, t); | |
| 1151 | + } | |
| 1152 | + | |
| 1153 | + // We create a stub for this. Source classes do more work. | |
| 1154 | + protected void basicCheck(Environment env) throws ClassNotFound { | |
| 1155 | + // Do the outer class first. | |
| 1156 | + if (outerClass != null) | |
| 1157 | + outerClass.basicCheck(env); | |
| 1158 | + } | |
| 1159 | + | |
| 1160 | + /** | |
| 1161 | + * Check this class. | |
| 1162 | + */ | |
| 1163 | + public void check(Environment env) throws ClassNotFound { | |
| 1164 | + } | |
| 1165 | + | |
| 1166 | + public Vset checkLocalClass(Environment env, Context ctx, | |
| 1167 | + Vset vset, ClassDefinition sup, | |
| 1168 | + Expression args[], Type argTypes[] | |
| 1169 | + ) throws ClassNotFound { | |
| 1170 | + throw new CompilerError("checkLocalClass"); | |
| 1171 | + } | |
| 1172 | + | |
| 1173 | + //--------------------------------------------------------------- | |
| 1174 | + // The non-synthetic methods defined in this class or in any | |
| 1175 | + // of its parents (class or interface). This member is used | |
| 1176 | + // to cache work done in collectInheritedMethods for use by | |
| 1177 | + // getMethods() and matchMethod(). It should be accessed by | |
| 1178 | + // no other method without forethought. | |
| 1179 | + MethodSet allMethods = null; | |
| 1180 | + | |
| 1181 | + // One of our superclasses may contain an abstract method which | |
| 1182 | + // we are unable to ever implement. This happens when there is | |
| 1183 | + // a package-private abstract method in our parent and we are in | |
| 1184 | + // a different package than our parent. In these cases, we | |
| 1185 | + // keep a list of the "permanently abstract" or "unimplementable" | |
| 1186 | + // methods so that we can correctly detect that this class is | |
| 1187 | + // indeed abstract and so that we can give somewhat comprehensible | |
| 1188 | + // error messages. | |
| 1189 | + private List permanentlyAbstractMethods = new ArrayList(); | |
| 1190 | + | |
| 1191 | + /** | |
| 1192 | + * This method returns an Iterator of all abstract methods | |
| 1193 | + * in our superclasses which we are unable to implement. | |
| 1194 | + */ | |
| 1195 | + protected Iterator getPermanentlyAbstractMethods() { | |
| 1196 | + // This method can only be called after collectInheritedMethods. | |
| 1197 | + if (allMethods == null) { | |
| 1198 | + throw new CompilerError("isPermanentlyAbstract() called early"); | |
| 1199 | + } | |
| 1200 | + | |
| 1201 | + return permanentlyAbstractMethods.iterator(); | |
| 1202 | + } | |
| 1203 | + | |
| 1204 | + /** | |
| 1205 | + * A flag used by turnOffInheritanceChecks() to indicate if | |
| 1206 | + * inheritance checks are on or off. | |
| 1207 | + */ | |
| 1208 | + protected static boolean doInheritanceChecks = true; | |
| 1209 | + | |
| 1210 | + /** | |
| 1211 | + * This is a workaround to allow javadoc to turn off certain | |
| 1212 | + * inheritance/override checks which interfere with javadoc | |
| 1213 | + * badly. In the future it might be good to eliminate the | |
| 1214 | + * shared sources of javadoc and javac to avoid the need for this | |
| 1215 | + * sort of workaround. | |
| 1216 | + */ | |
| 1217 | + public static void turnOffInheritanceChecks() { | |
| 1218 | + doInheritanceChecks = false; | |
| 1219 | + } | |
| 1220 | + | |
| 1221 | + /** | |
| 1222 | + * Add all of the methods declared in or above `parent' to | |
| 1223 | + * `allMethods', the set of methods in the current class. | |
| 1224 | + * `myMethods' is the set of all methods declared in this | |
| 1225 | + * class, and `mirandaMethods' is a repository for Miranda methods. | |
| 1226 | + * If mirandaMethods is null, no mirandaMethods will be | |
| 1227 | + * generated. | |
| 1228 | + * | |
| 1229 | + * For a definition of Miranda methods, see the comment above the | |
| 1230 | + * method addMirandaMethods() which occurs later in this file. | |
| 1231 | + */ | |
| 1232 | + private void collectOneClass(Environment env, | |
| 1233 | + ClassDeclaration parent, | |
| 1234 | + MethodSet myMethods, | |
| 1235 | + MethodSet allMethods, | |
| 1236 | + MethodSet mirandaMethods) { | |
| 1237 | + | |
| 1238 | + // System.out.println("Inheriting methods from " + parent); | |
| 1239 | + | |
| 1240 | + try { | |
| 1241 | + ClassDefinition pClass = parent.getClassDefinition(env); | |
| 1242 | + Iterator methods = pClass.getMethods(env); | |
| 1243 | + while (methods.hasNext()) { | |
| 1244 | + MemberDefinition method = | |
| 1245 | + (MemberDefinition) methods.next(); | |
| 1246 | + | |
| 1247 | + // Private methods are not inherited. | |
| 1248 | + // | |
| 1249 | + // Constructors are not inherited. | |
| 1250 | + // | |
| 1251 | + // Any non-abstract methods in an interface come | |
| 1252 | + // from java.lang.Object. This means that they | |
| 1253 | + // should have already been added to allMethods | |
| 1254 | + // when we walked our superclass lineage. | |
| 1255 | + if (method.isPrivate() || | |
| 1256 | + method.isConstructor() || | |
| 1257 | + (pClass.isInterface() && !method.isAbstract())) { | |
| 1258 | + | |
| 1259 | + continue; | |
| 1260 | + } | |
| 1261 | + | |
| 1262 | + // Get the components of the methods' signature. | |
| 1263 | + Identifier name = method.getName(); | |
| 1264 | + Type type = method.getType(); | |
| 1265 | + | |
| 1266 | + // Check for a method of the same signature which | |
| 1267 | + // was locally declared. | |
| 1268 | + MemberDefinition override = | |
| 1269 | + myMethods.lookupSig(name, type); | |
| 1270 | + | |
| 1271 | + // Is this method inaccessible due to package-private | |
| 1272 | + // visibility? | |
| 1273 | + if (method.isPackagePrivate() && | |
| 1274 | + !inSamePackage(method.getClassDeclaration())) { | |
| 1275 | + | |
| 1276 | + if (override != null && this instanceof | |
| 1277 | + sun.tools.javac.SourceClass) { | |
| 1278 | + // We give a warning when a class shadows an | |
| 1279 | + // inaccessible package-private method from | |
| 1280 | + // its superclass. This warning is meant | |
| 1281 | + // to prevent people from relying on overriding | |
| 1282 | + // when it does not happen. This warning should | |
| 1283 | + // probably be removed to be consistent with the | |
| 1284 | + // general "no warnings" policy of this | |
| 1285 | + // compiler. | |
| 1286 | + // | |
| 1287 | + // The `instanceof' above is a hack so that only | |
| 1288 | + // SourceClass generates this warning, not a | |
| 1289 | + // BinaryClass, for example. | |
| 1290 | + env.error(method.getWhere(), | |
| 1291 | + "warn.no.override.access", | |
| 1292 | + override, | |
| 1293 | + override.getClassDeclaration(), | |
| 1294 | + method.getClassDeclaration()); | |
| 1295 | + } | |
| 1296 | + | |
| 1297 | + // If our superclass has a package-private abstract | |
| 1298 | + // method that we have no access to, then we add | |
| 1299 | + // this method to our list of permanently abstract | |
| 1300 | + // methods. The idea is, since we cannot override | |
| 1301 | + // the method, we can never make this class | |
| 1302 | + // non-abstract. | |
| 1303 | + if (method.isAbstract()) { | |
| 1304 | + permanentlyAbstractMethods.add(method); | |
| 1305 | + } | |
| 1306 | + | |
| 1307 | + // `method' is inaccessible. We do not inherit it. | |
| 1308 | + continue; | |
| 1309 | + } | |
| 1310 | + | |
| 1311 | + if (override != null) { | |
| 1312 | + // `method' and `override' have the same signature. | |
| 1313 | + // We are required to check that `override' is a | |
| 1314 | + // legal override of `method' | |
| 1315 | + | |
| 1316 | + //System.out.println ("About to check override of " + | |
| 1317 | + // method); | |
| 1318 | + | |
| 1319 | + override.checkOverride(env, method); | |
| 1320 | + } else { | |
| 1321 | + // In the absence of a definition in the class | |
| 1322 | + // itself, we check to see if this definition | |
| 1323 | + // can be successfully merged with any other | |
| 1324 | + // inherited definitions. | |
| 1325 | + | |
| 1326 | + // Have we added a member of the same signature | |
| 1327 | + // to `allMethods' already? | |
| 1328 | + MemberDefinition formerMethod = | |
| 1329 | + allMethods.lookupSig(name, type); | |
| 1330 | + | |
| 1331 | + // If the previous definition is nonexistent or | |
| 1332 | + // ignorable, replace it. | |
| 1333 | + if (formerMethod == null) { | |
| 1334 | + //System.out.println("Added " + method + " to " + | |
| 1335 | + // this); | |
| 1336 | + | |
| 1337 | + if (mirandaMethods != null && | |
| 1338 | + pClass.isInterface() && !isInterface()) { | |
| 1339 | + // Whenever a class inherits a method | |
| 1340 | + // from an interface, that method is | |
| 1341 | + // one of our "miranda" methods. Early | |
| 1342 | + // VMs require that these methods be | |
| 1343 | + // added as true members to the class | |
| 1344 | + // to enable method lookup to work in the | |
| 1345 | + // VM. | |
| 1346 | + method = | |
| 1347 | + new sun.tools.javac.SourceMember(method,this, | |
| 1348 | + env); | |
| 1349 | + mirandaMethods.add(method); | |
| 1350 | + | |
| 1351 | + //System.out.println("Added " + method + | |
| 1352 | + // " to " + this + " as a Miranda"); | |
| 1353 | + } | |
| 1354 | + | |
| 1355 | + // There is no previous inherited definition. | |
| 1356 | + // Add `method' to `allMethods'. | |
| 1357 | + allMethods.add(method); | |
| 1358 | + } else if (isInterface() && | |
| 1359 | + !formerMethod.isAbstract() && | |
| 1360 | + method.isAbstract()) { | |
| 1361 | + // If we are in an interface and we have inherited | |
| 1362 | + // both an abstract method and a non-abstract method | |
| 1363 | + // then we know that the non-abstract method is | |
| 1364 | + // a placeholder from Object put in for type checking | |
| 1365 | + // and the abstract method was already checked to | |
| 1366 | + // be proper by our superinterface. | |
| 1367 | + allMethods.replace(method); | |
| 1368 | + | |
| 1369 | + } else { | |
| 1370 | + // Okay, `formerMethod' and `method' both have the | |
| 1371 | + // same signature. See if they are compatible. | |
| 1372 | + | |
| 1373 | + //System.out.println ("About to check meet of " + | |
| 1374 | + // method); | |
| 1375 | + | |
| 1376 | + if (!formerMethod.checkMeet(env, | |
| 1377 | + method, | |
| 1378 | + this.getClassDeclaration())) { | |
| 1379 | + // The methods are incompatible. Skip to | |
| 1380 | + // next method. | |
| 1381 | + continue; | |
| 1382 | + } | |
| 1383 | + | |
| 1384 | + if (formerMethod.couldOverride(env, method)) { | |
| 1385 | + // Do nothing. The current definition | |
| 1386 | + // is specific enough. | |
| 1387 | + | |
| 1388 | + //System.out.println("trivial meet of " + | |
| 1389 | + // method); | |
| 1390 | + continue; | |
| 1391 | + } | |
| 1392 | + | |
| 1393 | + if (method.couldOverride(env, formerMethod)) { | |
| 1394 | + // `method' is more specific than | |
| 1395 | + // `formerMethod'. replace `formerMethod'. | |
| 1396 | + | |
| 1397 | + //System.out.println("new def of " + method); | |
| 1398 | + if (mirandaMethods != null && | |
| 1399 | + pClass.isInterface() && !isInterface()) { | |
| 1400 | + // Whenever a class inherits a method | |
| 1401 | + // from an interface, that method is | |
| 1402 | + // one of our "miranda" methods. Early | |
| 1403 | + // VMs require that these methods be | |
| 1404 | + // added as true members to the class | |
| 1405 | + // to enable method lookup to work in the | |
| 1406 | + // VM. | |
| 1407 | + method = | |
| 1408 | + new sun.tools.javac.SourceMember(method, | |
| 1409 | + this,env); | |
| 1410 | + | |
| 1411 | + mirandaMethods.replace(method); | |
| 1412 | + | |
| 1413 | + //System.out.println("Added " + method + | |
| 1414 | + // " to " + this + " as a Miranda"); | |
| 1415 | + } | |
| 1416 | + | |
| 1417 | + allMethods.replace(method); | |
| 1418 | + | |
| 1419 | + continue; | |
| 1420 | + } | |
| 1421 | + | |
| 1422 | + // Neither method is more specific than the other. | |
| 1423 | + // Oh well. We need to construct a nontrivial | |
| 1424 | + // meet of the two methods. | |
| 1425 | + // | |
| 1426 | + // This is not yet implemented, so we give | |
| 1427 | + // a message with a helpful workaround. | |
| 1428 | + env.error(this.where, | |
| 1429 | + "nontrivial.meet", method, | |
| 1430 | + formerMethod.getClassDefinition(), | |
| 1431 | + method.getClassDeclaration() | |
| 1432 | + ); | |
| 1433 | + } | |
| 1434 | + } | |
| 1435 | + } | |
| 1436 | + } catch (ClassNotFound ee) { | |
| 1437 | + env.error(getWhere(), "class.not.found", ee.name, this); | |
| 1438 | + } | |
| 1439 | + } | |
| 1440 | + | |
| 1441 | + /** | |
| 1442 | + * <p>Collect all methods defined in this class or inherited from | |
| 1443 | + * any of our superclasses or interfaces. Look for any | |
| 1444 | + * incompatible definitions. | |
| 1445 | + * | |
| 1446 | + * <p>This function is also responsible for collecting the | |
| 1447 | + * <em>Miranda</em> methods for a class. For a definition of | |
| 1448 | + * Miranda methods, see the comment in addMirandaMethods() | |
| 1449 | + * below. | |
| 1450 | + */ | |
| 1451 | + protected void collectInheritedMethods(Environment env) { | |
| 1452 | + // The methods defined in this class. | |
| 1453 | + MethodSet myMethods; | |
| 1454 | + MethodSet mirandaMethods; | |
| 1455 | + | |
| 1456 | + //System.out.println("Called collectInheritedMethods() for " + | |
| 1457 | + // this); | |
| 1458 | + | |
| 1459 | + if (allMethods != null) { | |
| 1460 | + if (allMethods.isFrozen()) { | |
| 1461 | + // We have already done the collection. No need to | |
| 1462 | + // do it again. | |
| 1463 | + return; | |
| 1464 | + } else { | |
| 1465 | + // We have run into a circular need to collect our methods. | |
| 1466 | + // This should not happen at this stage. | |
| 1467 | + throw new CompilerError("collectInheritedMethods()"); | |
| 1468 | + } | |
| 1469 | + } | |
| 1470 | + | |
| 1471 | + myMethods = new MethodSet(); | |
| 1472 | + allMethods = new MethodSet(); | |
| 1473 | + | |
| 1474 | + // For testing, do not generate miranda methods. | |
| 1475 | + if (env.version12()) { | |
| 1476 | + mirandaMethods = null; | |
| 1477 | + } else { | |
| 1478 | + mirandaMethods = new MethodSet(); | |
| 1479 | + } | |
| 1480 | + | |
| 1481 | + // Any methods defined in the current class get added | |
| 1482 | + // to both the myMethods and the allMethods MethodSets. | |
| 1483 | + | |
| 1484 | + for (MemberDefinition member = getFirstMember(); | |
| 1485 | + member != null; | |
| 1486 | + member = member.nextMember) { | |
| 1487 | + | |
| 1488 | + // We only collect methods. Initializers are not relevant. | |
| 1489 | + if (member.isMethod() && | |
| 1490 | + !member.isInitializer()) { | |
| 1491 | + | |
| 1492 | + //System.out.println("Declared in " + this + ", " + member); | |
| 1493 | + | |
| 1494 | + //////////////////////////////////////////////////////////// | |
| 1495 | + // PCJ 2003-07-30 modified the following code because with | |
| 1496 | + // the covariant return type feature of the 1.5 compiler, | |
| 1497 | + // there might be multiple methods with the same signature | |
| 1498 | + // but different return types, and MethodSet doesn't | |
| 1499 | + // support that. We use a new utility method that attempts | |
| 1500 | + // to ensure that the appropriate method winds up in the | |
| 1501 | + // MethodSet. See 4892308. | |
| 1502 | + //////////////////////////////////////////////////////////// | |
| 1503 | + // myMethods.add(member); | |
| 1504 | + // allMethods.add(member); | |
| 1505 | + //////////////////////////////////////////////////////////// | |
| 1506 | + methodSetAdd(env, myMethods, member); | |
| 1507 | + methodSetAdd(env, allMethods, member); | |
| 1508 | + //////////////////////////////////////////////////////////// | |
| 1509 | + } | |
| 1510 | + } | |
| 1511 | + | |
| 1512 | + // We're ready to start adding inherited methods. First add | |
| 1513 | + // the methods from our superclass. | |
| 1514 | + | |
| 1515 | + //System.out.println("About to start superclasses for " + this); | |
| 1516 | + | |
| 1517 | + ClassDeclaration scDecl = getSuperClass(env); | |
| 1518 | + if (scDecl != null) { | |
| 1519 | + collectOneClass(env, scDecl, | |
| 1520 | + myMethods, allMethods, mirandaMethods); | |
| 1521 | + | |
| 1522 | + // Make sure that we add all unimplementable methods from our | |
| 1523 | + // superclass to our list of unimplementable methods. | |
| 1524 | + ClassDefinition sc = scDecl.getClassDefinition(); | |
| 1525 | + Iterator supIter = sc.getPermanentlyAbstractMethods(); | |
| 1526 | + while (supIter.hasNext()) { | |
| 1527 | + permanentlyAbstractMethods.add(supIter.next()); | |
| 1528 | + } | |
| 1529 | + } | |
| 1530 | + | |
| 1531 | + // Now we inherit all of the methods from our interfaces. | |
| 1532 | + | |
| 1533 | + //System.out.println("About to start interfaces for " + this); | |
| 1534 | + | |
| 1535 | + for (int i = 0; i < interfaces.length; i++) { | |
| 1536 | + collectOneClass(env, interfaces[i], | |
| 1537 | + myMethods, allMethods, mirandaMethods); | |
| 1538 | + } | |
| 1539 | + allMethods.freeze(); | |
| 1540 | + | |
| 1541 | + // Now we have collected all of our methods from our superclasses | |
| 1542 | + // and interfaces into our `allMethods' member. Good. As a last | |
| 1543 | + // task, we add our collected miranda methods to this class. | |
| 1544 | + // | |
| 1545 | + // If we do not add the mirandas to the class explicitly, there | |
| 1546 | + // will be no code generated for them. | |
| 1547 | + if (mirandaMethods != null && mirandaMethods.size() > 0) { | |
| 1548 | + addMirandaMethods(env, mirandaMethods.iterator()); | |
| 1549 | + } | |
| 1550 | + } | |
| 1551 | + | |
| 1552 | + //////////////////////////////////////////////////////////// | |
| 1553 | + // PCJ 2003-07-30 added this utility method to insulate | |
| 1554 | + // MethodSet additions from the covariant return type | |
| 1555 | + // feature of the 1.5 compiler. When there are multiple | |
| 1556 | + // methods with the same signature and different return | |
| 1557 | + // types to be added, we try to ensure that the one with | |
| 1558 | + // the most specific return type winds up in the MethodSet. | |
| 1559 | + // This logic was not put into MethodSet itself because it | |
| 1560 | + // requires access to an Environment for type relationship | |
| 1561 | + // checking. No error checking is performed here, but that | |
| 1562 | + // should be OK because this code is only still used by | |
| 1563 | + // rmic. See 4892308. | |
| 1564 | + //////////////////////////////////////////////////////////// | |
| 1565 | + private static void methodSetAdd(Environment env, | |
| 1566 | + MethodSet methodSet, | |
| 1567 | + MemberDefinition newMethod) | |
| 1568 | + { | |
| 1569 | + MemberDefinition oldMethod = methodSet.lookupSig(newMethod.getName(), | |
| 1570 | + newMethod.getType()); | |
| 1571 | + if (oldMethod != null) { | |
| 1572 | + Type oldReturnType = oldMethod.getType().getReturnType(); | |
| 1573 | + Type newReturnType = newMethod.getType().getReturnType(); | |
| 1574 | + try { | |
| 1575 | + if (env.isMoreSpecific(newReturnType, oldReturnType)) { | |
| 1576 | + methodSet.replace(newMethod); | |
| 1577 | + } | |
| 1578 | + } catch (ClassNotFound ignore) { | |
| 1579 | + } | |
| 1580 | + } else { | |
| 1581 | + methodSet.add(newMethod); | |
| 1582 | + } | |
| 1583 | + } | |
| 1584 | + //////////////////////////////////////////////////////////// | |
| 1585 | + | |
| 1586 | + /** | |
| 1587 | + * Get an Iterator of all methods which could be accessed in an | |
| 1588 | + * instance of this class. | |
| 1589 | + */ | |
| 1590 | + public Iterator getMethods(Environment env) { | |
| 1591 | + if (allMethods == null) { | |
| 1592 | + collectInheritedMethods(env); | |
| 1593 | + } | |
| 1594 | + return getMethods(); | |
| 1595 | + } | |
| 1596 | + | |
| 1597 | + /** | |
| 1598 | + * Get an Iterator of all methods which could be accessed in an | |
| 1599 | + * instance of this class. Throw a compiler error if we haven't | |
| 1600 | + * generated this information yet. | |
| 1601 | + */ | |
| 1602 | + public Iterator getMethods() { | |
| 1603 | + if (allMethods == null) { | |
| 1604 | + throw new CompilerError("getMethods: too early"); | |
| 1605 | + } | |
| 1606 | + return allMethods.iterator(); | |
| 1607 | + } | |
| 1608 | + | |
| 1609 | + // In early VM's there was a bug -- the VM didn't walk the interfaces | |
| 1610 | + // of a class looking for a method, they only walked the superclass | |
| 1611 | + // chain. This meant that abstract methods defined only in interfaces | |
| 1612 | + // were not being found. To fix this bug, a counter-bug was introduced | |
| 1613 | + // in the compiler -- the so-called Miranda methods. If a class | |
| 1614 | + // does not provide a definition for an abstract method in one of | |
| 1615 | + // its interfaces then the compiler inserts one in the class artificially. | |
| 1616 | + // That way the VM didn't have to bother looking at the interfaces. | |
| 1617 | + // | |
| 1618 | + // This is a problem. Miranda methods are not part of the specification. | |
| 1619 | + // But they continue to be inserted so that old VM's can run new code. | |
| 1620 | + // Someday, when the old VM's are gone, perhaps classes can be compiled | |
| 1621 | + // without Miranda methods. Towards this end, the compiler has a | |
| 1622 | + // flag, -nomiranda, which can turn off the creation of these methods. | |
| 1623 | + // Eventually that behavior should become the default. | |
| 1624 | + // | |
| 1625 | + // Why are they called Miranda methods? Well the sentence "If the | |
| 1626 | + // class is not able to provide a method, then one will be provided | |
| 1627 | + // by the compiler" is very similar to the sentence "If you cannot | |
| 1628 | + // afford an attorney, one will be provided by the court," -- one | |
| 1629 | + // of the so-called "Miranda" rights in the United States. | |
| 1630 | + | |
| 1631 | + /** | |
| 1632 | + * Add a list of methods to this class as miranda methods. This | |
| 1633 | + * gets overridden with a meaningful implementation in SourceClass. | |
| 1634 | + * BinaryClass should not need to do anything -- it should already | |
| 1635 | + * have its miranda methods and, if it doesn't, then that doesn't | |
| 1636 | + * affect our compilation. | |
| 1637 | + */ | |
| 1638 | + protected void addMirandaMethods(Environment env, | |
| 1639 | + Iterator mirandas) { | |
| 1640 | + // do nothing. | |
| 1641 | + } | |
| 1642 | + | |
| 1643 | + //--------------------------------------------------------------- | |
| 1644 | + | |
| 1645 | + public void inlineLocalClass(Environment env) { | |
| 1646 | + } | |
| 1647 | + | |
| 1648 | + /** | |
| 1649 | + * We create a stub for this. Source classes do more work. | |
| 1650 | + * Some calls from 'SourceClass.checkSupers' execute this method. | |
| 1651 | + * @see sun.tools.javac.SourceClass#resolveTypeStructure | |
| 1652 | + */ | |
| 1653 | + | |
| 1654 | + public void resolveTypeStructure(Environment env) { | |
| 1655 | + } | |
| 1656 | + | |
| 1657 | + /** | |
| 1658 | + * Look up an inner class name, from somewhere inside this class. | |
| 1659 | + * Since supers and outers are in scope, search them too. | |
| 1660 | + * <p> | |
| 1661 | + * If no inner class is found, env.resolveName() is then called, | |
| 1662 | + * to interpret the ambient package and import directives. | |
| 1663 | + * <p> | |
| 1664 | + * This routine operates on a "best-efforts" basis. If | |
| 1665 | + * at some point a class is not found, the partially-resolved | |
| 1666 | + * identifier is returned. Eventually, someone else has to | |
| 1667 | + * try to get the ClassDefinition and diagnose the ClassNotFound. | |
| 1668 | + * <p> | |
| 1669 | + * resolveName() looks at surrounding scopes, and hence | |
| 1670 | + * pulling in both inherited and uplevel types. By contrast, | |
| 1671 | + * resolveInnerClass() is intended only for interpreting | |
| 1672 | + * explicitly qualified names, and so look only at inherited | |
| 1673 | + * types. Also, resolveName() looks for package prefixes, | |
| 1674 | + * which appear similar to "very uplevel" outer classes. | |
| 1675 | + * <p> | |
| 1676 | + * A similar (but more complex) name-lookup process happens | |
| 1677 | + * when field and identifier expressions denoting qualified names | |
| 1678 | + * are type-checked. The added complexity comes from the fact | |
| 1679 | + * that variables may occur in such names, and take precedence | |
| 1680 | + * over class and package names. | |
| 1681 | + * <p> | |
| 1682 | + * In the expression type-checker, resolveInnerClass() is paralleled | |
| 1683 | + * by code in FieldExpression.checkAmbigName(), which also calls | |
| 1684 | + * ClassDefinition.getInnerClass() to interpret names of the form | |
| 1685 | + * "OuterClass.Inner" (and also outerObject.Inner). The checking | |
| 1686 | + * of an identifier expression that fails to be a variable is referred | |
| 1687 | + * directly to resolveName(). | |
| 1688 | + */ | |
| 1689 | + public Identifier resolveName(Environment env, Identifier name) { | |
| 1690 | + if (tracing) env.dtEvent("ClassDefinition.resolveName: " + name); | |
| 1691 | + // This logic is pretty much exactly parallel to that of | |
| 1692 | + // Environment.resolveName(). | |
| 1693 | + if (name.isQualified()) { | |
| 1694 | + // Try to resolve the first identifier component, | |
| 1695 | + // because inner class names take precedence over | |
| 1696 | + // package prefixes. (Cf. Environment.resolveName.) | |
| 1697 | + Identifier rhead = resolveName(env, name.getHead()); | |
| 1698 | + | |
| 1699 | + if (rhead.hasAmbigPrefix()) { | |
| 1700 | + // The first identifier component refers to an | |
| 1701 | + // ambiguous class. Limp on. We throw away the | |
| 1702 | + // rest of the classname as it is irrelevant. | |
| 1703 | + // (part of solution for 4059855). | |
| 1704 | + return rhead; | |
| 1705 | + } | |
| 1706 | + | |
| 1707 | + if (!env.classExists(rhead)) { | |
| 1708 | + return env.resolvePackageQualifiedName(name); | |
| 1709 | + } | |
| 1710 | + try { | |
| 1711 | + return env.getClassDefinition(rhead). | |
| 1712 | + resolveInnerClass(env, name.getTail()); | |
| 1713 | + } catch (ClassNotFound ee) { | |
| 1714 | + // return partially-resolved name someone else can fail on | |
| 1715 | + return Identifier.lookupInner(rhead, name.getTail()); | |
| 1716 | + } | |
| 1717 | + } | |
| 1718 | + | |
| 1719 | + // This method used to fail to look for local classes, thus a | |
| 1720 | + // reference to a local class within, e.g., the type of a member | |
| 1721 | + // declaration, would fail to resolve if the immediately enclosing | |
| 1722 | + // context was an inner class. The code added below is ugly, but | |
| 1723 | + // it works, and is lifted from existing code in 'Context.resolveName' | |
| 1724 | + // and 'Context.getClassCommon'. See the comments there about the design. | |
| 1725 | + // Fixes 4095716. | |
| 1726 | + | |
| 1727 | + int ls = -2; | |
| 1728 | + LocalMember lf = null; | |
| 1729 | + if (classContext != null) { | |
| 1730 | + lf = classContext.getLocalClass(name); | |
| 1731 | + if (lf != null) { | |
| 1732 | + ls = lf.getScopeNumber(); | |
| 1733 | + } | |
| 1734 | + } | |
| 1735 | + | |
| 1736 | + // Look for an unqualified name in enclosing scopes. | |
| 1737 | + for (ClassDefinition c = this; c != null; c = c.outerClass) { | |
| 1738 | + try { | |
| 1739 | + MemberDefinition f = c.getInnerClass(env, name); | |
| 1740 | + if (f != null && | |
| 1741 | + (lf == null || classContext.getScopeNumber(c) > ls)) { | |
| 1742 | + // An uplevel member was found, and was nested more deeply than | |
| 1743 | + // any enclosing local of the same name. | |
| 1744 | + return f.getInnerClass().getName(); | |
| 1745 | + } | |
| 1746 | + } catch (ClassNotFound ee) { | |
| 1747 | + // a missing superclass, or something catastrophic | |
| 1748 | + } | |
| 1749 | + } | |
| 1750 | + | |
| 1751 | + // No uplevel member found, so use the enclosing local if one was found. | |
| 1752 | + if (lf != null) { | |
| 1753 | + return lf.getInnerClass().getName(); | |
| 1754 | + } | |
| 1755 | + | |
| 1756 | + // look in imports, etc. | |
| 1757 | + return env.resolveName(name); | |
| 1758 | + } | |
| 1759 | + | |
| 1760 | + /** | |
| 1761 | + * Interpret a qualified class name, which may have further subcomponents.. | |
| 1762 | + * Follow inheritance links, as in: | |
| 1763 | + * class C { class N { } } class D extends C { } ... new D.N() ... | |
| 1764 | + * Ignore outer scopes and packages. | |
| 1765 | + * @see resolveName | |
| 1766 | + */ | |
| 1767 | + public Identifier resolveInnerClass(Environment env, Identifier nm) { | |
| 1768 | + if (nm.isInner()) throw new CompilerError("inner"); | |
| 1769 | + if (nm.isQualified()) { | |
| 1770 | + Identifier rhead = resolveInnerClass(env, nm.getHead()); | |
| 1771 | + try { | |
| 1772 | + return env.getClassDefinition(rhead). | |
| 1773 | + resolveInnerClass(env, nm.getTail()); | |
| 1774 | + } catch (ClassNotFound ee) { | |
| 1775 | + // return partially-resolved name someone else can fail on | |
| 1776 | + return Identifier.lookupInner(rhead, nm.getTail()); | |
| 1777 | + } | |
| 1778 | + } else { | |
| 1779 | + try { | |
| 1780 | + MemberDefinition f = getInnerClass(env, nm); | |
| 1781 | + if (f != null) { | |
| 1782 | + return f.getInnerClass().getName(); | |
| 1783 | + } | |
| 1784 | + } catch (ClassNotFound ee) { | |
| 1785 | + // a missing superclass, or something catastrophic | |
| 1786 | + } | |
| 1787 | + // Fake a good name for a diagnostic. | |
| 1788 | + return Identifier.lookupInner(this.getName(), nm); | |
| 1789 | + } | |
| 1790 | + } | |
| 1791 | + | |
| 1792 | + /** | |
| 1793 | + * While resolving import directives, the question has arisen: | |
| 1794 | + * does a given inner class exist? If the top-level class exists, | |
| 1795 | + * we ask it about an inner class via this method. | |
| 1796 | + * This method looks only at the literal name of the class, | |
| 1797 | + * and does not attempt to follow inheritance links. | |
| 1798 | + * This is necessary, since at the time imports are being | |
| 1799 | + * processed, inheritance links have not been resolved yet. | |
| 1800 | + * (Thus, an import directive must always spell a class | |
| 1801 | + * name exactly.) | |
| 1802 | + */ | |
| 1803 | + public boolean innerClassExists(Identifier nm) { | |
| 1804 | + for (MemberDefinition field = getFirstMatch(nm.getHead()) ; field != null ; field = field.getNextMatch()) { | |
| 1805 | + if (field.isInnerClass()) { | |
| 1806 | + if (field.getInnerClass().isLocal()) { | |
| 1807 | + continue; // ignore this name; it is internally generated | |
| 1808 | + } | |
| 1809 | + return !nm.isQualified() || | |
| 1810 | + field.getInnerClass().innerClassExists(nm.getTail()); | |
| 1811 | + } | |
| 1812 | + } | |
| 1813 | + return false; | |
| 1814 | + } | |
| 1815 | + | |
| 1816 | + /** | |
| 1817 | + * Find any method with a given name. | |
| 1818 | + */ | |
| 1819 | + public MemberDefinition findAnyMethod(Environment env, Identifier nm) throws ClassNotFound { | |
| 1820 | + MemberDefinition f; | |
| 1821 | + for (f = getFirstMatch(nm) ; f != null ; f = f.getNextMatch()) { | |
| 1822 | + if (f.isMethod()) { | |
| 1823 | + return f; | |
| 1824 | + } | |
| 1825 | + } | |
| 1826 | + | |
| 1827 | + // look in the super class | |
| 1828 | + ClassDeclaration sup = getSuperClass(); | |
| 1829 | + if (sup == null) | |
| 1830 | + return null; | |
| 1831 | + return sup.getClassDefinition(env).findAnyMethod(env, nm); | |
| 1832 | + } | |
| 1833 | + | |
| 1834 | + /** | |
| 1835 | + * Given the fact that this class has no method "nm" matching "argTypes", | |
| 1836 | + * find out if the mismatch can be blamed on a particular actual argument | |
| 1837 | + * which disagrees with all of the overloadings. | |
| 1838 | + * If so, return the code (i<<2)+(castOK<<1)+ambig, where | |
| 1839 | + * "i" is the number of the offending argument, and | |
| 1840 | + * "castOK" is 1 if a cast could fix the problem. | |
| 1841 | + * The target type for the argument is returned in margTypeResult[0]. | |
| 1842 | + * If not all methods agree on this type, "ambig" is 1. | |
| 1843 | + * If there is more than one method, the choice of target type is | |
| 1844 | + * arbitrary.<p> | |
| 1845 | + * Return -1 if every argument is acceptable to at least one method. | |
| 1846 | + * Return -2 if there are no methods of the required arity. | |
| 1847 | + * The value "start" gives the index of the first argument to begin | |
| 1848 | + * checking. | |
| 1849 | + */ | |
| 1850 | + public int diagnoseMismatch(Environment env, Identifier nm, Type argTypes[], | |
| 1851 | + int start, Type margTypeResult[]) throws ClassNotFound { | |
| 1852 | + int haveMatch[] = new int[argTypes.length]; | |
| 1853 | + Type margType[] = new Type[argTypes.length]; | |
| 1854 | + if (!diagnoseMismatch(env, nm, argTypes, start, haveMatch, margType)) | |
| 1855 | + return -2; | |
| 1856 | + for (int i = start; i < argTypes.length; i++) { | |
| 1857 | + if (haveMatch[i] < 4) { | |
| 1858 | + margTypeResult[0] = margType[i]; | |
| 1859 | + return (i<<2) | haveMatch[i]; | |
| 1860 | + } | |
| 1861 | + } | |
| 1862 | + return -1; | |
| 1863 | + } | |
| 1864 | + | |
| 1865 | + private boolean diagnoseMismatch(Environment env, Identifier nm, Type argTypes[], int start, | |
| 1866 | + int haveMatch[], Type margType[]) throws ClassNotFound { | |
| 1867 | + // look in the current class | |
| 1868 | + boolean haveOne = false; | |
| 1869 | + MemberDefinition f; | |
| 1870 | + for (f = getFirstMatch(nm) ; f != null ; f = f.getNextMatch()) { | |
| 1871 | + if (!f.isMethod()) { | |
| 1872 | + continue; | |
| 1873 | + } | |
| 1874 | + Type fArgTypes[] = f.getType().getArgumentTypes(); | |
| 1875 | + if (fArgTypes.length == argTypes.length) { | |
| 1876 | + haveOne = true; | |
| 1877 | + for (int i = start; i < argTypes.length; i++) { | |
| 1878 | + Type at = argTypes[i]; | |
| 1879 | + Type ft = fArgTypes[i]; | |
| 1880 | + if (env.implicitCast(at, ft)) { | |
| 1881 | + haveMatch[i] = 4; | |
| 1882 | + continue; | |
| 1883 | + } else if (haveMatch[i] <= 2 && env.explicitCast(at, ft)) { | |
| 1884 | + if (haveMatch[i] < 2) margType[i] = null; | |
| 1885 | + haveMatch[i] = 2; | |
| 1886 | + } else if (haveMatch[i] > 0) { | |
| 1887 | + continue; | |
| 1888 | + } | |
| 1889 | + if (margType[i] == null) | |
| 1890 | + margType[i] = ft; | |
| 1891 | + else if (margType[i] != ft) | |
| 1892 | + haveMatch[i] |= 1; | |
| 1893 | + } | |
| 1894 | + } | |
| 1895 | + } | |
| 1896 | + | |
| 1897 | + // constructors are not inherited | |
| 1898 | + if (nm.equals(idInit)) { | |
| 1899 | + return haveOne; | |
| 1900 | + } | |
| 1901 | + | |
| 1902 | + // look in the super class | |
| 1903 | + ClassDeclaration sup = getSuperClass(); | |
| 1904 | + if (sup != null) { | |
| 1905 | + if (sup.getClassDefinition(env).diagnoseMismatch(env, nm, argTypes, start, | |
| 1906 | + haveMatch, margType)) | |
| 1907 | + haveOne = true; | |
| 1908 | + } | |
| 1909 | + return haveOne; | |
| 1910 | + } | |
| 1911 | + | |
| 1912 | + /** | |
| 1913 | + * Add a field (no checks) | |
| 1914 | + */ | |
| 1915 | + public void addMember(MemberDefinition field) { | |
| 1916 | + //System.out.println("ADD = " + field); | |
| 1917 | + if (firstMember == null) { | |
| 1918 | + firstMember = lastMember = field; | |
| 1919 | + } else if (field.isSynthetic() && field.isFinal() | |
| 1920 | + && field.isVariable()) { | |
| 1921 | + // insert this at the front, because of initialization order | |
| 1922 | + field.nextMember = firstMember; | |
| 1923 | + firstMember = field; | |
| 1924 | + field.nextMatch = (MemberDefinition)fieldHash.get(field.name); | |
| 1925 | + } else { | |
| 1926 | + lastMember.nextMember = field; | |
| 1927 | + lastMember = field; | |
| 1928 | + field.nextMatch = (MemberDefinition)fieldHash.get(field.name); | |
| 1929 | + } | |
| 1930 | + fieldHash.put(field.name, field); | |
| 1931 | + } | |
| 1932 | + | |
| 1933 | + /** | |
| 1934 | + * Add a field (subclasses make checks) | |
| 1935 | + */ | |
| 1936 | + public void addMember(Environment env, MemberDefinition field) { | |
| 1937 | + addMember(field); | |
| 1938 | + if (resolved) { | |
| 1939 | + // a late addition | |
| 1940 | + field.resolveTypeStructure(env); | |
| 1941 | + } | |
| 1942 | + } | |
| 1943 | + | |
| 1944 | + /** | |
| 1945 | + * Find or create an uplevel reference for the given target. | |
| 1946 | + */ | |
| 1947 | + public UplevelReference getReference(LocalMember target) { | |
| 1948 | + for (UplevelReference r = references; r != null; r = r.getNext()) { | |
| 1949 | + if (r.getTarget() == target) { | |
| 1950 | + return r; | |
| 1951 | + } | |
| 1952 | + } | |
| 1953 | + return addReference(target); | |
| 1954 | + } | |
| 1955 | + | |
| 1956 | + protected UplevelReference addReference(LocalMember target) { | |
| 1957 | + if (target.getClassDefinition() == this) { | |
| 1958 | + throw new CompilerError("addReference "+target); | |
| 1959 | + } | |
| 1960 | + referencesMustNotBeFrozen(); | |
| 1961 | + UplevelReference r = new UplevelReference(this, target); | |
| 1962 | + references = r.insertInto(references); | |
| 1963 | + return r; | |
| 1964 | + } | |
| 1965 | + | |
| 1966 | + /** | |
| 1967 | + * Return the list of all uplevel references. | |
| 1968 | + */ | |
| 1969 | + public UplevelReference getReferences() { | |
| 1970 | + return references; | |
| 1971 | + } | |
| 1972 | + | |
| 1973 | + /** | |
| 1974 | + * Return the same value as getReferences. | |
| 1975 | + * Also, mark the set of references frozen. | |
| 1976 | + * After that, it is an error to add new references. | |
| 1977 | + */ | |
| 1978 | + public UplevelReference getReferencesFrozen() { | |
| 1979 | + referencesFrozen = true; | |
| 1980 | + return references; | |
| 1981 | + } | |
| 1982 | + | |
| 1983 | + /** | |
| 1984 | + * assertion check | |
| 1985 | + */ | |
| 1986 | + public final void referencesMustNotBeFrozen() { | |
| 1987 | + if (referencesFrozen) { | |
| 1988 | + throw new CompilerError("referencesMustNotBeFrozen "+this); | |
| 1989 | + } | |
| 1990 | + } | |
| 1991 | + | |
| 1992 | + /** | |
| 1993 | + * Get helper method for class literal lookup. | |
| 1994 | + */ | |
| 1995 | + public MemberDefinition getClassLiteralLookup(long fwhere) { | |
| 1996 | + throw new CompilerError("binary class"); | |
| 1997 | + } | |
| 1998 | + | |
| 1999 | + /** | |
| 2000 | + * Add a dependency | |
| 2001 | + */ | |
| 2002 | + public void addDependency(ClassDeclaration c) { | |
| 2003 | + throw new CompilerError("addDependency"); | |
| 2004 | + } | |
| 2005 | + | |
| 2006 | + /** | |
| 2007 | + * Maintain a hash table of local and anonymous classes | |
| 2008 | + * whose internal names are prefixed by the current class. | |
| 2009 | + * The key is the simple internal name, less the prefix. | |
| 2010 | + */ | |
| 2011 | + | |
| 2012 | + public ClassDefinition getLocalClass(String name) { | |
| 2013 | + if (localClasses == null) { | |
| 2014 | + return null; | |
| 2015 | + } else { | |
| 2016 | + return (ClassDefinition)localClasses.get(name); | |
| 2017 | + } | |
| 2018 | + } | |
| 2019 | + | |
| 2020 | + public void addLocalClass(ClassDefinition c, String name) { | |
| 2021 | + if (localClasses == null) { | |
| 2022 | + localClasses = new Hashtable(LOCAL_CLASSES_SIZE); | |
| 2023 | + } | |
| 2024 | + localClasses.put(name, c); | |
| 2025 | + } | |
| 2026 | + | |
| 2027 | + | |
| 2028 | + /** | |
| 2029 | + * Print for debugging | |
| 2030 | + */ | |
| 2031 | + public void print(PrintStream out) { | |
| 2032 | + if (isPublic()) { | |
| 2033 | + out.print("public "); | |
| 2034 | + } | |
| 2035 | + if (isInterface()) { | |
| 2036 | + out.print("interface "); | |
| 2037 | + } else { | |
| 2038 | + out.print("class "); | |
| 2039 | + } | |
| 2040 | + out.print(getName() + " "); | |
| 2041 | + if (getSuperClass() != null) { | |
| 2042 | + out.print("extends " + getSuperClass().getName() + " "); | |
| 2043 | + } | |
| 2044 | + if (interfaces.length > 0) { | |
| 2045 | + out.print("implements "); | |
| 2046 | + for (int i = 0 ; i < interfaces.length ; i++) { | |
| 2047 | + if (i > 0) { | |
| 2048 | + out.print(", "); | |
| 2049 | + } | |
| 2050 | + out.print(interfaces[i].getName()); | |
| 2051 | + out.print(" "); | |
| 2052 | + } | |
| 2053 | + } | |
| 2054 | + out.println("{"); | |
| 2055 | + | |
| 2056 | + for (MemberDefinition f = getFirstMember() ; f != null ; f = f.getNextMember()) { | |
| 2057 | + out.print(" "); | |
| 2058 | + f.print(out); | |
| 2059 | + } | |
| 2060 | + | |
| 2061 | + out.println("}"); | |
| 2062 | + } | |
| 2063 | + | |
| 2064 | + /** | |
| 2065 | + * Convert to String | |
| 2066 | + */ | |
| 2067 | + public String toString() { | |
| 2068 | + return getClassDeclaration().toString(); | |
| 2069 | + } | |
| 2070 | + | |
| 2071 | + /** | |
| 2072 | + * After the class has been written to disk, try to free up | |
| 2073 | + * some storage. | |
| 2074 | + */ | |
| 2075 | + public void cleanup(Environment env) { | |
| 2076 | + if (env.dump()) { | |
| 2077 | + env.output("[cleanup " + getName() + "]"); | |
| 2078 | + } | |
| 2079 | + for (MemberDefinition f = getFirstMember() ; f != null ; f = f.getNextMember()) { | |
| 2080 | + f.cleanup(env); | |
| 2081 | + } | |
| 2082 | + // keep "references" around, for the sake of local subclasses | |
| 2083 | + documentation = null; | |
| 2084 | + } | |
| 2085 | +} | |
| @@ -0,0 +1,162 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +import java.io.File; | |
| 29 | +import java.io.InputStream; | |
| 30 | +import java.io.FileInputStream; | |
| 31 | +import java.io.IOException; | |
| 32 | +import java.util.zip.*; | |
| 33 | + | |
| 34 | +/** | |
| 35 | + * This class is used to represent a file loaded from the class path, and | |
| 36 | + * can either be a regular file or a zip file entry. | |
| 37 | + * | |
| 38 | + * WARNING: The contents of this source file are not part of any | |
| 39 | + * supported API. Code that depends on them does so at its own risk: | |
| 40 | + * they are subject to change or removal without notice. | |
| 41 | + */ | |
| 42 | +public | |
| 43 | +class ClassFile { | |
| 44 | + /* | |
| 45 | + * Non-null if this represents a regular file | |
| 46 | + */ | |
| 47 | + private File file; | |
| 48 | + | |
| 49 | + /* | |
| 50 | + * Non-null if this represents a zip file entry | |
| 51 | + */ | |
| 52 | + private ZipFile zipFile; | |
| 53 | + private ZipEntry zipEntry; | |
| 54 | + | |
| 55 | + /** | |
| 56 | + * Constructor for instance representing a regular file | |
| 57 | + */ | |
| 58 | + public ClassFile(File file) { | |
| 59 | + this.file = file; | |
| 60 | + } | |
| 61 | + | |
| 62 | + /** | |
| 63 | + * Constructor for instance representing a zip file entry | |
| 64 | + */ | |
| 65 | + public ClassFile(ZipFile zf, ZipEntry ze) { | |
| 66 | + this.zipFile = zf; | |
| 67 | + this.zipEntry = ze; | |
| 68 | + } | |
| 69 | + | |
| 70 | + /** | |
| 71 | + * Returns true if this is zip file entry | |
| 72 | + */ | |
| 73 | + public boolean isZipped() { | |
| 74 | + return zipFile != null; | |
| 75 | + } | |
| 76 | + | |
| 77 | + /** | |
| 78 | + * Returns input stream to either regular file or zip file entry | |
| 79 | + */ | |
| 80 | + public InputStream getInputStream() throws IOException { | |
| 81 | + if (file != null) { | |
| 82 | + return new FileInputStream(file); | |
| 83 | + } else { | |
| 84 | + try { | |
| 85 | + return zipFile.getInputStream(zipEntry); | |
| 86 | + } catch (ZipException e) { | |
| 87 | + throw new IOException(e.getMessage()); | |
| 88 | + } | |
| 89 | + } | |
| 90 | + } | |
| 91 | + | |
| 92 | + /** | |
| 93 | + * Returns true if file exists. | |
| 94 | + */ | |
| 95 | + public boolean exists() { | |
| 96 | + return file != null ? file.exists() : true; | |
| 97 | + } | |
| 98 | + | |
| 99 | + /** | |
| 100 | + * Returns true if this is a directory. | |
| 101 | + */ | |
| 102 | + public boolean isDirectory() { | |
| 103 | + return file != null ? file.isDirectory() : | |
| 104 | + zipEntry.getName().endsWith("/"); | |
| 105 | + } | |
| 106 | + | |
| 107 | + /** | |
| 108 | + * Return last modification time | |
| 109 | + */ | |
| 110 | + public long lastModified() { | |
| 111 | + return file != null ? file.lastModified() : zipEntry.getTime(); | |
| 112 | + } | |
| 113 | + | |
| 114 | + /** | |
| 115 | + * Get file path. The path for a zip file entry will also include | |
| 116 | + * the zip file name. | |
| 117 | + */ | |
| 118 | + public String getPath() { | |
| 119 | + if (file != null) { | |
| 120 | + return file.getPath(); | |
| 121 | + } else { | |
| 122 | + return zipFile.getName() + "(" + zipEntry.getName() + ")"; | |
| 123 | + } | |
| 124 | + } | |
| 125 | + | |
| 126 | + /** | |
| 127 | + * Get name of file entry excluding directory name | |
| 128 | + */ | |
| 129 | + public String getName() { | |
| 130 | + return file != null ? file.getName() : zipEntry.getName(); | |
| 131 | + } | |
| 132 | + | |
| 133 | +//JCOV | |
| 134 | + /** | |
| 135 | + * Get absolute name of file entry | |
| 136 | + */ | |
| 137 | + public String getAbsoluteName() { | |
| 138 | + String absoluteName; | |
| 139 | + if (file != null) { | |
| 140 | + try { | |
| 141 | + absoluteName = file.getCanonicalPath(); | |
| 142 | + } catch (IOException e) { | |
| 143 | + absoluteName = file.getAbsolutePath(); | |
| 144 | + } | |
| 145 | + } else { | |
| 146 | + absoluteName = zipFile.getName() + "(" + zipEntry.getName() + ")"; | |
| 147 | + } | |
| 148 | + return absoluteName; | |
| 149 | + } | |
| 150 | +// end JCOV | |
| 151 | + | |
| 152 | + /** | |
| 153 | + * Get length of file | |
| 154 | + */ | |
| 155 | + public long length() { | |
| 156 | + return file != null ? file.length() : zipEntry.getSize(); | |
| 157 | + } | |
| 158 | + | |
| 159 | + public String toString() { | |
| 160 | + return (file != null) ? file.toString() : zipEntry.toString(); | |
| 161 | + } | |
| 162 | +} | |
| @@ -0,0 +1,50 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This exception is thrown when a class definition is needed | |
| 30 | + * and the class can't be found. | |
| 31 | + * | |
| 32 | + * WARNING: The contents of this source file are not part of any | |
| 33 | + * supported API. Code that depends on them does so at its own risk: | |
| 34 | + * they are subject to change or removal without notice. | |
| 35 | + */ | |
| 36 | +public | |
| 37 | +class ClassNotFound extends Exception { | |
| 38 | + /** | |
| 39 | + * The class that was not found | |
| 40 | + */ | |
| 41 | + public Identifier name; | |
| 42 | + | |
| 43 | + /** | |
| 44 | + * Create a ClassNotFound exception | |
| 45 | + */ | |
| 46 | + public ClassNotFound(Identifier nm) { | |
| 47 | + super(nm.toString()); | |
| 48 | + name = nm; | |
| 49 | + } | |
| 50 | +} | |
| @@ -0,0 +1,314 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2007, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +import java.util.Enumeration; | |
| 29 | +import java.util.Hashtable; | |
| 30 | +import java.io.File; | |
| 31 | +import java.io.IOException; | |
| 32 | +import java.util.zip.*; | |
| 33 | + | |
| 34 | +/** | |
| 35 | + * This class is used to represent a class path, which can contain both | |
| 36 | + * directories and zip files. | |
| 37 | + * | |
| 38 | + * WARNING: The contents of this source file are not part of any | |
| 39 | + * supported API. Code that depends on them does so at its own risk: | |
| 40 | + * they are subject to change or removal without notice. | |
| 41 | + */ | |
| 42 | +public | |
| 43 | +class ClassPath { | |
| 44 | + static final char dirSeparator = File.pathSeparatorChar; | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * The original class path string | |
| 48 | + */ | |
| 49 | + String pathstr; | |
| 50 | + | |
| 51 | + /** | |
| 52 | + * List of class path entries | |
| 53 | + */ | |
| 54 | + private ClassPathEntry[] path; | |
| 55 | + | |
| 56 | + /** | |
| 57 | + * Build a class path from the specified path string | |
| 58 | + */ | |
| 59 | + public ClassPath(String pathstr) { | |
| 60 | + init(pathstr); | |
| 61 | + } | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * Build a class path from the specified array of class path | |
| 65 | + * element strings. This constructor, and the corresponding | |
| 66 | + * "init" method, were added as part of the fix for 6473331, which | |
| 67 | + * adds support for Class-Path manifest entries in JAR files to | |
| 68 | + * rmic. It is conceivable that the value of a Class-Path | |
| 69 | + * manifest entry will contain a path separator, which would cause | |
| 70 | + * incorrect behavior if the expanded path were passed to the | |
| 71 | + * previous constructor as a single path-separator-delimited | |
| 72 | + * string; use of this constructor avoids that problem. | |
| 73 | + */ | |
| 74 | + public ClassPath(String[] patharray) { | |
| 75 | + init(patharray); | |
| 76 | + } | |
| 77 | + | |
| 78 | + /** | |
| 79 | + * Build a default class path from the path strings specified by | |
| 80 | + * the properties sun.boot.class.path and env.class.path, in that | |
| 81 | + * order. | |
| 82 | + */ | |
| 83 | + public ClassPath() { | |
| 84 | + String syscp = System.getProperty("sun.boot.class.path"); | |
| 85 | + String envcp = System.getProperty("env.class.path"); | |
| 86 | + if (envcp == null) envcp = "."; | |
| 87 | + String cp = syscp + File.pathSeparator + envcp; | |
| 88 | + init(cp); | |
| 89 | + } | |
| 90 | + | |
| 91 | + private void init(String pathstr) { | |
| 92 | + int i, j, n; | |
| 93 | + // Save original class path string | |
| 94 | + this.pathstr = pathstr; | |
| 95 | + | |
| 96 | + if (pathstr.length() == 0) { | |
| 97 | + this.path = new ClassPathEntry[0]; | |
| 98 | + } | |
| 99 | + | |
| 100 | + // Count the number of path separators | |
| 101 | + i = n = 0; | |
| 102 | + while ((i = pathstr.indexOf(dirSeparator, i)) != -1) { | |
| 103 | + n++; i++; | |
| 104 | + } | |
| 105 | + // Build the class path | |
| 106 | + ClassPathEntry[] path = new ClassPathEntry[n+1]; | |
| 107 | + int len = pathstr.length(); | |
| 108 | + for (i = n = 0; i < len; i = j + 1) { | |
| 109 | + if ((j = pathstr.indexOf(dirSeparator, i)) == -1) { | |
| 110 | + j = len; | |
| 111 | + } | |
| 112 | + if (i == j) { | |
| 113 | + path[n] = new ClassPathEntry(); | |
| 114 | + path[n++].dir = new File("."); | |
| 115 | + } else { | |
| 116 | + File file = new File(pathstr.substring(i, j)); | |
| 117 | + if (file.isFile()) { | |
| 118 | + try { | |
| 119 | + ZipFile zip = new ZipFile(file); | |
| 120 | + path[n] = new ClassPathEntry(); | |
| 121 | + path[n++].zip = zip; | |
| 122 | + } catch (ZipException e) { | |
| 123 | + } catch (IOException e) { | |
| 124 | + // Ignore exceptions, at least for now... | |
| 125 | + } | |
| 126 | + } else { | |
| 127 | + path[n] = new ClassPathEntry(); | |
| 128 | + path[n++].dir = file; | |
| 129 | + } | |
| 130 | + } | |
| 131 | + } | |
| 132 | + // Trim class path to exact size | |
| 133 | + this.path = new ClassPathEntry[n]; | |
| 134 | + System.arraycopy((Object)path, 0, (Object)this.path, 0, n); | |
| 135 | + } | |
| 136 | + | |
| 137 | + private void init(String[] patharray) { | |
| 138 | + // Save original class path string | |
| 139 | + if (patharray.length == 0) { | |
| 140 | + this.pathstr = ""; | |
| 141 | + } else { | |
| 142 | + StringBuilder sb = new StringBuilder(patharray[0]); | |
| 143 | + for (int i = 1; i < patharray.length; i++) { | |
| 144 | + sb.append(File.separator); | |
| 145 | + sb.append(patharray[i]); | |
| 146 | + } | |
| 147 | + this.pathstr = sb.toString(); | |
| 148 | + } | |
| 149 | + | |
| 150 | + // Build the class path | |
| 151 | + ClassPathEntry[] path = new ClassPathEntry[patharray.length]; | |
| 152 | + int n = 0; | |
| 153 | + for (String name : patharray) { | |
| 154 | + File file = new File(name); | |
| 155 | + if (file.isFile()) { | |
| 156 | + try { | |
| 157 | + ZipFile zip = new ZipFile(file); | |
| 158 | + path[n] = new ClassPathEntry(); | |
| 159 | + path[n++].zip = zip; | |
| 160 | + } catch (ZipException e) { | |
| 161 | + } catch (IOException e) { | |
| 162 | + // Ignore exceptions, at least for now... | |
| 163 | + } | |
| 164 | + } else { | |
| 165 | + path[n] = new ClassPathEntry(); | |
| 166 | + path[n++].dir = file; | |
| 167 | + } | |
| 168 | + } | |
| 169 | + // Trim class path to exact size | |
| 170 | + this.path = new ClassPathEntry[n]; | |
| 171 | + System.arraycopy((Object)path, 0, (Object)this.path, 0, n); | |
| 172 | + } | |
| 173 | + | |
| 174 | + /** | |
| 175 | + * Find the specified directory in the class path | |
| 176 | + */ | |
| 177 | + public ClassFile getDirectory(String name) { | |
| 178 | + return getFile(name, true); | |
| 179 | + } | |
| 180 | + | |
| 181 | + /** | |
| 182 | + * Load the specified file from the class path | |
| 183 | + */ | |
| 184 | + public ClassFile getFile(String name) { | |
| 185 | + return getFile(name, false); | |
| 186 | + } | |
| 187 | + | |
| 188 | + private final String fileSeparatorChar = "" + File.separatorChar; | |
| 189 | + | |
| 190 | + private ClassFile getFile(String name, boolean isDirectory) { | |
| 191 | + String subdir = name; | |
| 192 | + String basename = ""; | |
| 193 | + if (!isDirectory) { | |
| 194 | + int i = name.lastIndexOf(File.separatorChar); | |
| 195 | + subdir = name.substring(0, i + 1); | |
| 196 | + basename = name.substring(i + 1); | |
| 197 | + } else if (!subdir.equals("") | |
| 198 | + && !subdir.endsWith(fileSeparatorChar)) { | |
| 199 | + // zip files are picky about "foo" vs. "foo/". | |
| 200 | + // also, the getFiles caches are keyed with a trailing / | |
| 201 | + subdir = subdir + File.separatorChar; | |
| 202 | + name = subdir; // Note: isDirectory==true & basename=="" | |
| 203 | + } | |
| 204 | + for (int i = 0; i < path.length; i++) { | |
| 205 | + if (path[i].zip != null) { | |
| 206 | + String newname = name.replace(File.separatorChar, '/'); | |
| 207 | + ZipEntry entry = path[i].zip.getEntry(newname); | |
| 208 | + if (entry != null) { | |
| 209 | + return new ClassFile(path[i].zip, entry); | |
| 210 | + } | |
| 211 | + } else { | |
| 212 | + File file = new File(path[i].dir.getPath(), name); | |
| 213 | + String list[] = path[i].getFiles(subdir); | |
| 214 | + if (isDirectory) { | |
| 215 | + if (list.length > 0) { | |
| 216 | + return new ClassFile(file); | |
| 217 | + } | |
| 218 | + } else { | |
| 219 | + for (int j = 0; j < list.length; j++) { | |
| 220 | + if (basename.equals(list[j])) { | |
| 221 | + // Don't bother checking !file.isDir, | |
| 222 | + // since we only look for names which | |
| 223 | + // cannot already be packages (foo.java, etc). | |
| 224 | + return new ClassFile(file); | |
| 225 | + } | |
| 226 | + } | |
| 227 | + } | |
| 228 | + } | |
| 229 | + } | |
| 230 | + return null; | |
| 231 | + } | |
| 232 | + | |
| 233 | + /** | |
| 234 | + * Returns list of files given a package name and extension. | |
| 235 | + */ | |
| 236 | + public Enumeration getFiles(String pkg, String ext) { | |
| 237 | + Hashtable files = new Hashtable(); | |
| 238 | + for (int i = path.length; --i >= 0; ) { | |
| 239 | + if (path[i].zip != null) { | |
| 240 | + Enumeration e = path[i].zip.entries(); | |
| 241 | + while (e.hasMoreElements()) { | |
| 242 | + ZipEntry entry = (ZipEntry)e.nextElement(); | |
| 243 | + String name = entry.getName(); | |
| 244 | + name = name.replace('/', File.separatorChar); | |
| 245 | + if (name.startsWith(pkg) && name.endsWith(ext)) { | |
| 246 | + files.put(name, new ClassFile(path[i].zip, entry)); | |
| 247 | + } | |
| 248 | + } | |
| 249 | + } else { | |
| 250 | + String[] list = path[i].getFiles(pkg); | |
| 251 | + for (int j = 0; j < list.length; j++) { | |
| 252 | + String name = list[j]; | |
| 253 | + if (name.endsWith(ext)) { | |
| 254 | + name = pkg + File.separatorChar + name; | |
| 255 | + File file = new File(path[i].dir.getPath(), name); | |
| 256 | + files.put(name, new ClassFile(file)); | |
| 257 | + } | |
| 258 | + } | |
| 259 | + } | |
| 260 | + } | |
| 261 | + return files.elements(); | |
| 262 | + } | |
| 263 | + | |
| 264 | + /** | |
| 265 | + * Release resources. | |
| 266 | + */ | |
| 267 | + public void close() throws IOException { | |
| 268 | + for (int i = path.length; --i >= 0; ) { | |
| 269 | + if (path[i].zip != null) { | |
| 270 | + path[i].zip.close(); | |
| 271 | + } | |
| 272 | + } | |
| 273 | + } | |
| 274 | + | |
| 275 | + /** | |
| 276 | + * Returns original class path string | |
| 277 | + */ | |
| 278 | + public String toString() { | |
| 279 | + return pathstr; | |
| 280 | + } | |
| 281 | +} | |
| 282 | + | |
| 283 | +/** | |
| 284 | + * A class path entry, which can either be a directory or an open zip file. | |
| 285 | + */ | |
| 286 | +class ClassPathEntry { | |
| 287 | + File dir; | |
| 288 | + ZipFile zip; | |
| 289 | + | |
| 290 | + Hashtable subdirs = new Hashtable(29); // cache of sub-directory listings | |
| 291 | + String[] getFiles(String subdir) { | |
| 292 | + String files[] = (String[]) subdirs.get(subdir); | |
| 293 | + if (files == null) { | |
| 294 | + // search the directory, exactly once | |
| 295 | + File sd = new File(dir.getPath(), subdir); | |
| 296 | + if (sd.isDirectory()) { | |
| 297 | + files = sd.list(); | |
| 298 | + if (files == null) { | |
| 299 | + // should not happen, but just in case, fail silently | |
| 300 | + files = new String[0]; | |
| 301 | + } | |
| 302 | + if (files.length == 0) { | |
| 303 | + String nonEmpty[] = { "" }; | |
| 304 | + files = nonEmpty; | |
| 305 | + } | |
| 306 | + } else { | |
| 307 | + files = new String[0]; | |
| 308 | + } | |
| 309 | + subdirs.put(subdir, files); | |
| 310 | + } | |
| 311 | + return files; | |
| 312 | + } | |
| 313 | + | |
| 314 | +} | |
| @@ -0,0 +1,64 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This class represents an Java class type. | |
| 30 | + * It overrides the relevant methods in class Type. | |
| 31 | + * | |
| 32 | + * WARNING: The contents of this source file are not part of any | |
| 33 | + * supported API. Code that depends on them does so at its own risk: | |
| 34 | + * they are subject to change or removal without notice. | |
| 35 | + * | |
| 36 | + * @author Arthur van Hoff | |
| 37 | + */ | |
| 38 | +public final | |
| 39 | +class ClassType extends Type { | |
| 40 | + /** | |
| 41 | + * The fully qualified class name. | |
| 42 | + */ | |
| 43 | + Identifier className; | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * Construct a class type. Use Type.tClass to create | |
| 47 | + * a new class type. | |
| 48 | + */ | |
| 49 | + ClassType(String typeSig, Identifier className) { | |
| 50 | + super(TC_CLASS, typeSig); | |
| 51 | + this.className = className; | |
| 52 | + } | |
| 53 | + | |
| 54 | + public Identifier getClassName() { | |
| 55 | + return className; | |
| 56 | + } | |
| 57 | + | |
| 58 | + public String typeString(String id, boolean abbrev, boolean ret) { | |
| 59 | + String s = (abbrev ? getClassName().getFlatName() : | |
| 60 | + Identifier.lookup(getClassName().getQualifier(), | |
| 61 | + getClassName().getFlatName())).toString(); | |
| 62 | + return (id.length() > 0) ? s + " " + id : s; | |
| 63 | + } | |
| 64 | +} | |
| @@ -0,0 +1,62 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This exception is thrown when an internal compiler error occurs | |
| 30 | + * | |
| 31 | + * WARNING: The contents of this source file are not part of any | |
| 32 | + * supported API. Code that depends on them does so at its own risk: | |
| 33 | + * they are subject to change or removal without notice. | |
| 34 | + */ | |
| 35 | + | |
| 36 | +public | |
| 37 | +class CompilerError extends Error { | |
| 38 | + Throwable e; | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * Constructor | |
| 42 | + */ | |
| 43 | + public CompilerError(String msg) { | |
| 44 | + super(msg); | |
| 45 | + this.e = this; | |
| 46 | + } | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * Create an exception given another exception. | |
| 50 | + */ | |
| 51 | + public CompilerError(Exception e) { | |
| 52 | + super(e.getMessage()); | |
| 53 | + this.e = e; | |
| 54 | + } | |
| 55 | + | |
| 56 | + public void printStackTrace() { | |
| 57 | + if (e == this) | |
| 58 | + super.printStackTrace(); | |
| 59 | + else | |
| 60 | + e.printStackTrace(); | |
| 61 | + } | |
| 62 | +} | |
| @@ -0,0 +1,591 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | + | |
| 27 | +package sun.tools.java; | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * This interface defines constant that are used | |
| 31 | + * throughout the compiler. It inherits from RuntimeConstants, | |
| 32 | + * which is an autogenerated class that contains contstants | |
| 33 | + * defined in the interpreter. | |
| 34 | + * | |
| 35 | + * WARNING: The contents of this source file are not part of any | |
| 36 | + * supported API. Code that depends on them does so at its own risk: | |
| 37 | + * they are subject to change or removal without notice. | |
| 38 | + * | |
| 39 | + * @author Arthur van Hoff | |
| 40 | + */ | |
| 41 | + | |
| 42 | +public | |
| 43 | +interface Constants extends RuntimeConstants { | |
| 44 | + | |
| 45 | + /* | |
| 46 | + * Enable/disable inclusion of certain debug tracing code in the | |
| 47 | + * compiler. When included, the tracing code may be selectively | |
| 48 | + * enabled at runtime, otherwise we save the space/time overhead. | |
| 49 | + * Should normally be 'false' for a release version. | |
| 50 | + */ | |
| 51 | + public static final boolean tracing = true; | |
| 52 | + | |
| 53 | + /* | |
| 54 | + * Frequently used identifiers | |
| 55 | + */ | |
| 56 | + Identifier idAppend = Identifier.lookup("append"); | |
| 57 | + Identifier idClassInit = Identifier.lookup("<clinit>"); | |
| 58 | + Identifier idCode = Identifier.lookup("Code"); | |
| 59 | + Identifier idInit = Identifier.lookup("<init>"); | |
| 60 | + Identifier idLength = Identifier.lookup("length"); | |
| 61 | + Identifier idNull = Identifier.lookup(""); | |
| 62 | + Identifier idStar = Identifier.lookup("*"); | |
| 63 | + Identifier idSuper = Identifier.lookup("super"); | |
| 64 | + Identifier idThis = Identifier.lookup("this"); | |
| 65 | + Identifier idClass = Identifier.lookup("class"); | |
| 66 | + Identifier idToString = Identifier.lookup("toString"); | |
| 67 | + Identifier idValueOf = Identifier.lookup("valueOf"); | |
| 68 | + Identifier idNew = Identifier.lookup("new"); | |
| 69 | + Identifier idGetClass = Identifier.lookup("getClass"); | |
| 70 | + Identifier idTYPE = Identifier.lookup("TYPE"); | |
| 71 | + Identifier idFinallyReturnValue = Identifier.lookup("<return>"); | |
| 72 | + | |
| 73 | + Identifier idJavaLang = Identifier.lookup("java.lang"); | |
| 74 | + | |
| 75 | + Identifier idJavaLangCloneable = Identifier.lookup("java.lang.Cloneable"); | |
| 76 | + | |
| 77 | + Identifier idJavaLangError = Identifier.lookup("java.lang.Error"); | |
| 78 | + Identifier idJavaLangException = Identifier.lookup("java.lang.Exception"); | |
| 79 | + Identifier idJavaLangObject = Identifier.lookup("java.lang.Object"); | |
| 80 | + Identifier idJavaLangClass = Identifier.lookup("java.lang.Class"); | |
| 81 | + Identifier idJavaLangRuntimeException = | |
| 82 | + Identifier.lookup("java.lang.RuntimeException"); | |
| 83 | + Identifier idJavaLangString = Identifier.lookup("java.lang.String"); | |
| 84 | + Identifier idJavaLangStringBuffer = | |
| 85 | + Identifier.lookup("java.lang.StringBuffer"); | |
| 86 | + Identifier idJavaLangThrowable = Identifier.lookup("java.lang.Throwable"); | |
| 87 | + | |
| 88 | + Identifier idJavaIoSerializable = Identifier.lookup("java.io.Serializable"); | |
| 89 | + | |
| 90 | + | |
| 91 | + Identifier idConstantValue = Identifier.lookup("ConstantValue"); | |
| 92 | + Identifier idLocalVariableTable = Identifier.lookup("LocalVariableTable"); | |
| 93 | + Identifier idLineNumberTable = Identifier.lookup("LineNumberTable"); | |
| 94 | +// JCOV | |
| 95 | + Identifier idCoverageTable = Identifier.lookup("CoverageTable"); | |
| 96 | +// end JCOV | |
| 97 | + Identifier idSourceFile = Identifier.lookup("SourceFile"); | |
| 98 | + Identifier idDocumentation = Identifier.lookup("Documentation"); | |
| 99 | + Identifier idDeprecated = Identifier.lookup("Deprecated"); | |
| 100 | + Identifier idSynthetic = Identifier.lookup("Synthetic"); | |
| 101 | + Identifier idExceptions = Identifier.lookup("Exceptions"); | |
| 102 | + Identifier idInnerClasses = Identifier.lookup("InnerClasses"); | |
| 103 | + | |
| 104 | + /* methods we need to know about */ | |
| 105 | + Identifier idClone = Identifier.lookup("clone"); | |
| 106 | + | |
| 107 | + | |
| 108 | + /* This is not a real signature marker, since it is also | |
| 109 | + * an identifier constituent character. | |
| 110 | + */ | |
| 111 | + char SIGC_INNERCLASS = '$'; | |
| 112 | + String SIG_INNERCLASS = "$"; | |
| 113 | + | |
| 114 | + String prefixThis = "this$"; | |
| 115 | + String prefixVal = "val$"; | |
| 116 | + String prefixLoc = "loc$"; | |
| 117 | + String prefixAccess = "access$"; | |
| 118 | + String prefixClass = "class$"; | |
| 119 | + String prefixArray = "array$"; | |
| 120 | + | |
| 121 | + /* | |
| 122 | + * Flags | |
| 123 | + */ | |
| 124 | + int F_VERBOSE = 1 << 0; | |
| 125 | + int F_DUMP = 1 << 1; | |
| 126 | + int F_WARNINGS = 1 << 2; | |
| 127 | + | |
| 128 | + // The meaning of -g has changed, so F_DEBUG flag is removed. | |
| 129 | + // public static final int F_DEBUG = 1 << 3; | |
| 130 | + int F_DEBUG_LINES = 1 << 12; | |
| 131 | + int F_DEBUG_VARS = 1 << 13; | |
| 132 | + int F_DEBUG_SOURCE = 1 << 18; | |
| 133 | + | |
| 134 | + // The meaning of -O has changed, so F_OPTIMIZE flag is removed. | |
| 135 | + // public static final int F_OPTIMIZE = 1 << 4; | |
| 136 | + int F_OPT = 1 << 14; | |
| 137 | + int F_OPT_INTERCLASS = 1 << 15; | |
| 138 | + | |
| 139 | + int F_DEPENDENCIES = 1 << 5; | |
| 140 | + | |
| 141 | +// JCOV | |
| 142 | + int F_COVERAGE = 1 << 6; | |
| 143 | + int F_COVDATA = 1 << 7; | |
| 144 | +// end JCOV | |
| 145 | + | |
| 146 | + int F_DEPRECATION = 1 << 9; | |
| 147 | + int F_PRINT_DEPENDENCIES = 1 << 10; | |
| 148 | + int F_VERSION12 = 1 << 11; | |
| 149 | + | |
| 150 | + | |
| 151 | + int F_ERRORSREPORTED = 1 << 16; | |
| 152 | + | |
| 153 | + int F_STRICTDEFAULT = 1 << 17; | |
| 154 | + | |
| 155 | + /* | |
| 156 | + * Modifiers. | |
| 157 | + * | |
| 158 | + * There has been much confusion regarding modifiers. There | |
| 159 | + * are a number of distinct usages: | |
| 160 | + * | |
| 161 | + * - in classfiles to annotate classes, as per JVM pg. 102. | |
| 162 | + * - in classfiles to annotate methods, as per JVM pg. 104. | |
| 163 | + * - in classfiles to annotate InnerClass attributes, as per | |
| 164 | + * http://java.sun.com/products/jdk/1.1/docs/guide/innerclasses | |
| 165 | + * - in the compiler to record java source level modifiers, | |
| 166 | + * as per JLS pg. 157 et al., plus misc. info such as whether | |
| 167 | + * a method is deprecated | |
| 168 | + * - in the JVM to record misc. info, such as whether a method has | |
| 169 | + * has been compiled | |
| 170 | + * | |
| 171 | + * To make matters worse, the terms "access flags" and "modifiers" | |
| 172 | + * are often used interchangably, and some information that might | |
| 173 | + * make sense as a flag is expressed using attributes (ie. Synthetic). | |
| 174 | + * | |
| 175 | + * The constants defined herein have been divided by whether they | |
| 176 | + * make sense only within the compiler (M_* and MM_*) or whether | |
| 177 | + * they only make sense to the JVM (ACC_* and ACCM_*). At an earlier | |
| 178 | + * time these were all lumped together. Future maintenance should | |
| 179 | + * strive to keep the distinction clear. | |
| 180 | + * | |
| 181 | + * Note that modifier M_STRICTFP is not in general recoverable from | |
| 182 | + * the ACC_STRICT bit in classfiles. | |
| 183 | + * | |
| 184 | + * Note also that the modifiers M_LOCAL and M_ANONYMOUS do not appear | |
| 185 | + * in the InnerClass attribute, as they are above the first 16 bits. | |
| 186 | + */ | |
| 187 | + | |
| 188 | + // Modifiers meaningful to both Java source and the JVM. These | |
| 189 | + // have been kept the same bit in the M_* and ACC_* forms | |
| 190 | + // to avoid destabilizing the compiler. | |
| 191 | + int M_PUBLIC = ACC_PUBLIC; | |
| 192 | + int M_PRIVATE = ACC_PRIVATE; | |
| 193 | + int M_PROTECTED = ACC_PROTECTED; | |
| 194 | + int M_STATIC = ACC_STATIC; | |
| 195 | + int M_TRANSIENT = ACC_TRANSIENT; | |
| 196 | + int M_SYNCHRONIZED = ACC_SYNCHRONIZED; // collides with ACC_SUPER | |
| 197 | + int M_ABSTRACT = ACC_ABSTRACT; | |
| 198 | + int M_NATIVE = ACC_NATIVE; | |
| 199 | + int M_FINAL = ACC_FINAL; | |
| 200 | + int M_VOLATILE = ACC_VOLATILE; | |
| 201 | + int M_INTERFACE = ACC_INTERFACE; | |
| 202 | + | |
| 203 | + // Modifiers not meaningful to the JVM. The JVM only allows 16 bits | |
| 204 | + // for modifiers, so keeping these in the unusable bits after the first | |
| 205 | + // 16 is a good idea. | |
| 206 | + int M_ANONYMOUS = 0x00010000; | |
| 207 | + int M_LOCAL = 0x00020000; | |
| 208 | + int M_DEPRECATED = 0x00040000; | |
| 209 | + int M_SYNTHETIC = 0x00080000; | |
| 210 | + int M_INLINEABLE = 0x00100000; | |
| 211 | + | |
| 212 | + int M_STRICTFP = 0x00200000; | |
| 213 | + | |
| 214 | + String paraDeprecated = "@deprecated"; | |
| 215 | + | |
| 216 | + // Masks for modifiers that apply to Java source code | |
| 217 | + int MM_CLASS = M_PUBLIC | |
| 218 | + | M_INTERFACE | |
| 219 | + | M_FINAL | |
| 220 | + | M_ABSTRACT | |
| 221 | + | M_STRICTFP; | |
| 222 | + int MM_MEMBER = M_PUBLIC | |
| 223 | + | M_PRIVATE | |
| 224 | + | M_PROTECTED | |
| 225 | + | M_FINAL | |
| 226 | + | M_STATIC; | |
| 227 | + int MM_FIELD = MM_MEMBER | |
| 228 | + | M_TRANSIENT | |
| 229 | + | M_VOLATILE; | |
| 230 | + int MM_METHOD = MM_MEMBER | |
| 231 | + | M_SYNCHRONIZED | |
| 232 | + | M_ABSTRACT | |
| 233 | + | M_NATIVE | |
| 234 | + | M_STRICTFP; | |
| 235 | + | |
| 236 | + // Masks for modifiers that apply to class files. | |
| 237 | + // Note that the M_SYNTHETIC modifier is never written out to a class file. | |
| 238 | + // Synthetic members are indicated using the "Synthetic" attribute. | |
| 239 | + int ACCM_CLASS = ACC_PUBLIC | |
| 240 | + | ACC_INTERFACE | |
| 241 | + | ACC_FINAL | |
| 242 | + | ACC_ABSTRACT | |
| 243 | + | ACC_SUPER | |
| 244 | + | ACC_STRICT; | |
| 245 | + int ACCM_MEMBER = ACC_PUBLIC | |
| 246 | + | ACC_PRIVATE | |
| 247 | + | ACC_PROTECTED | |
| 248 | + | ACC_FINAL | |
| 249 | + | ACC_STATIC; | |
| 250 | + // The M_ANONYMOUS and M_LOCAL modifiers are not mentioned in the | |
| 251 | + // inner classes specification and are never written to classfiles. | |
| 252 | + // Also note that ACC_SUPER should never be set in an InnerClass | |
| 253 | + // attribute. | |
| 254 | + int ACCM_INNERCLASS = ACC_PUBLIC | |
| 255 | + | ACC_PRIVATE | |
| 256 | + | ACC_PROTECTED | |
| 257 | + | ACC_STATIC | |
| 258 | + | ACC_ABSTRACT | |
| 259 | + | ACC_FINAL | |
| 260 | + | ACC_INTERFACE | |
| 261 | + | ACC_STRICT; | |
| 262 | + int ACCM_FIELD = ACCM_MEMBER | |
| 263 | + | ACC_TRANSIENT | |
| 264 | + | ACC_VOLATILE; | |
| 265 | + int ACCM_METHOD = ACCM_MEMBER | |
| 266 | + | ACC_SYNCHRONIZED | |
| 267 | + | ACC_ABSTRACT | |
| 268 | + | ACC_NATIVE | |
| 269 | + | ACC_STRICT; | |
| 270 | + | |
| 271 | + /* | |
| 272 | + * Type codes | |
| 273 | + */ | |
| 274 | + int TC_BOOLEAN = 0; | |
| 275 | + int TC_BYTE = 1; | |
| 276 | + int TC_CHAR = 2; | |
| 277 | + int TC_SHORT = 3; | |
| 278 | + int TC_INT = 4; | |
| 279 | + int TC_LONG = 5; | |
| 280 | + int TC_FLOAT = 6; | |
| 281 | + int TC_DOUBLE = 7; | |
| 282 | + int TC_NULL = 8; | |
| 283 | + int TC_ARRAY = 9; | |
| 284 | + int TC_CLASS = 10; | |
| 285 | + int TC_VOID = 11; | |
| 286 | + int TC_METHOD = 12; | |
| 287 | + int TC_ERROR = 13; | |
| 288 | + | |
| 289 | +// JCOV | |
| 290 | + /* | |
| 291 | + * Cover's types | |
| 292 | + */ | |
| 293 | + int CT_FIRST_KIND = 1; | |
| 294 | + int CT_METHOD = 1; | |
| 295 | + int CT_FIKT_METHOD = 2; | |
| 296 | + int CT_BLOCK = 3; | |
| 297 | + int CT_FIKT_RET = 4; | |
| 298 | + int CT_CASE = 5; | |
| 299 | + int CT_SWITH_WO_DEF = 6; | |
| 300 | + int CT_BRANCH_TRUE = 7; | |
| 301 | + int CT_BRANCH_FALSE = 8; | |
| 302 | + int CT_LAST_KIND = 8; | |
| 303 | +// end JCOV | |
| 304 | + | |
| 305 | + /* | |
| 306 | + * Type Masks | |
| 307 | + */ | |
| 308 | + int TM_NULL = 1 << TC_NULL; | |
| 309 | + int TM_VOID = 1 << TC_VOID; | |
| 310 | + int TM_BOOLEAN = 1 << TC_BOOLEAN; | |
| 311 | + int TM_BYTE = 1 << TC_BYTE; | |
| 312 | + int TM_CHAR = 1 << TC_CHAR; | |
| 313 | + int TM_SHORT = 1 << TC_SHORT; | |
| 314 | + int TM_INT = 1 << TC_INT; | |
| 315 | + int TM_LONG = 1 << TC_LONG; | |
| 316 | + int TM_FLOAT = 1 << TC_FLOAT; | |
| 317 | + int TM_DOUBLE = 1 << TC_DOUBLE; | |
| 318 | + int TM_ARRAY = 1 << TC_ARRAY; | |
| 319 | + int TM_CLASS = 1 << TC_CLASS; | |
| 320 | + int TM_METHOD = 1 << TC_METHOD; | |
| 321 | + int TM_ERROR = 1 << TC_ERROR; | |
| 322 | + | |
| 323 | + int TM_INT32 = TM_BYTE | TM_SHORT | TM_CHAR | TM_INT; | |
| 324 | + int TM_NUM32 = TM_INT32 | TM_FLOAT; | |
| 325 | + int TM_NUM64 = TM_LONG | TM_DOUBLE; | |
| 326 | + int TM_INTEGER = TM_INT32 | TM_LONG; | |
| 327 | + int TM_REAL = TM_FLOAT | TM_DOUBLE; | |
| 328 | + int TM_NUMBER = TM_INTEGER | TM_REAL; | |
| 329 | + int TM_REFERENCE = TM_ARRAY | TM_CLASS | TM_NULL; | |
| 330 | + | |
| 331 | + /* | |
| 332 | + * Class status | |
| 333 | + */ | |
| 334 | + int CS_UNDEFINED = 0; | |
| 335 | + int CS_UNDECIDED = 1; | |
| 336 | + int CS_BINARY = 2; | |
| 337 | + int CS_SOURCE = 3; | |
| 338 | + int CS_PARSED = 4; | |
| 339 | + int CS_CHECKED = 5; | |
| 340 | + int CS_COMPILED = 6; | |
| 341 | + int CS_NOTFOUND = 7; | |
| 342 | + | |
| 343 | + | |
| 344 | + /* | |
| 345 | + * Attributes | |
| 346 | + */ | |
| 347 | + int ATT_ALL = 0xFFFFFFFF; | |
| 348 | + int ATT_CODE = 1 << 1; | |
| 349 | + int ATT_ALLCLASSES = 1 << 2; | |
| 350 | + | |
| 351 | + /* | |
| 352 | + * Number of bits used in file offsets. The line number and | |
| 353 | + * file offset are concatenated into a long, with enough room | |
| 354 | + * for other information to be added later if desired (such as | |
| 355 | + * token lengths). For the moment explicit bit manipulations | |
| 356 | + * are used to modify the fields. This makes sense for efficiency | |
| 357 | + * but at some point these ought to be better encapsulated. | |
| 358 | + */ | |
| 359 | + int WHEREOFFSETBITS = 32; | |
| 360 | + long MAXFILESIZE = (1L << WHEREOFFSETBITS) - 1; | |
| 361 | + long MAXLINENUMBER = (1L << (64 - WHEREOFFSETBITS)) - 1; | |
| 362 | + | |
| 363 | + /* | |
| 364 | + * Operators | |
| 365 | + */ | |
| 366 | + int COMMA = 0; | |
| 367 | + int ASSIGN = 1; | |
| 368 | + | |
| 369 | + int ASGMUL = 2; | |
| 370 | + int ASGDIV = 3; | |
| 371 | + int ASGREM = 4; | |
| 372 | + int ASGADD = 5; | |
| 373 | + int ASGSUB = 6; | |
| 374 | + int ASGLSHIFT = 7; | |
| 375 | + int ASGRSHIFT = 8; | |
| 376 | + int ASGURSHIFT = 9; | |
| 377 | + int ASGBITAND = 10; | |
| 378 | + int ASGBITOR = 11; | |
| 379 | + int ASGBITXOR = 12; | |
| 380 | + | |
| 381 | + int COND = 13; | |
| 382 | + int OR = 14; | |
| 383 | + int AND = 15; | |
| 384 | + int BITOR = 16; | |
| 385 | + int BITXOR = 17; | |
| 386 | + int BITAND = 18; | |
| 387 | + int NE = 19; | |
| 388 | + int EQ = 20; | |
| 389 | + int GE = 21; | |
| 390 | + int GT = 22; | |
| 391 | + int LE = 23; | |
| 392 | + int LT = 24; | |
| 393 | + int INSTANCEOF = 25; | |
| 394 | + int LSHIFT = 26; | |
| 395 | + int RSHIFT = 27; | |
| 396 | + int URSHIFT = 28; | |
| 397 | + int ADD = 29; | |
| 398 | + int SUB = 30; | |
| 399 | + int DIV = 31; | |
| 400 | + int REM = 32; | |
| 401 | + int MUL = 33; | |
| 402 | + int CAST = 34; // (x)y | |
| 403 | + int POS = 35; // +x | |
| 404 | + int NEG = 36; // -x | |
| 405 | + int NOT = 37; | |
| 406 | + int BITNOT = 38; | |
| 407 | + int PREINC = 39; // ++x | |
| 408 | + int PREDEC = 40; // --x | |
| 409 | + int NEWARRAY = 41; | |
| 410 | + int NEWINSTANCE = 42; | |
| 411 | + int NEWFROMNAME = 43; | |
| 412 | + int POSTINC = 44; // x++ | |
| 413 | + int POSTDEC = 45; // x-- | |
| 414 | + int FIELD = 46; | |
| 415 | + int METHOD = 47; // x(y) | |
| 416 | + int ARRAYACCESS = 48; // x[y] | |
| 417 | + int NEW = 49; | |
| 418 | + int INC = 50; | |
| 419 | + int DEC = 51; | |
| 420 | + | |
| 421 | + int CONVERT = 55; // implicit conversion | |
| 422 | + int EXPR = 56; // (x) | |
| 423 | + int ARRAY = 57; // {x, y, ...} | |
| 424 | + int GOTO = 58; | |
| 425 | + | |
| 426 | + /* | |
| 427 | + * Value tokens | |
| 428 | + */ | |
| 429 | + int IDENT = 60; | |
| 430 | + int BOOLEANVAL = 61; | |
| 431 | + int BYTEVAL = 62; | |
| 432 | + int CHARVAL = 63; | |
| 433 | + int SHORTVAL = 64; | |
| 434 | + int INTVAL = 65; | |
| 435 | + int LONGVAL = 66; | |
| 436 | + int FLOATVAL = 67; | |
| 437 | + int DOUBLEVAL = 68; | |
| 438 | + int STRINGVAL = 69; | |
| 439 | + | |
| 440 | + /* | |
| 441 | + * Type keywords | |
| 442 | + */ | |
| 443 | + int BYTE = 70; | |
| 444 | + int CHAR = 71; | |
| 445 | + int SHORT = 72; | |
| 446 | + int INT = 73; | |
| 447 | + int LONG = 74; | |
| 448 | + int FLOAT = 75; | |
| 449 | + int DOUBLE = 76; | |
| 450 | + int VOID = 77; | |
| 451 | + int BOOLEAN = 78; | |
| 452 | + | |
| 453 | + /* | |
| 454 | + * Expression keywords | |
| 455 | + */ | |
| 456 | + int TRUE = 80; | |
| 457 | + int FALSE = 81; | |
| 458 | + int THIS = 82; | |
| 459 | + int SUPER = 83; | |
| 460 | + int NULL = 84; | |
| 461 | + | |
| 462 | + /* | |
| 463 | + * Statement keywords | |
| 464 | + */ | |
| 465 | + int IF = 90; | |
| 466 | + int ELSE = 91; | |
| 467 | + int FOR = 92; | |
| 468 | + int WHILE = 93; | |
| 469 | + int DO = 94; | |
| 470 | + int SWITCH = 95; | |
| 471 | + int CASE = 96; | |
| 472 | + int DEFAULT = 97; | |
| 473 | + int BREAK = 98; | |
| 474 | + int CONTINUE = 99; | |
| 475 | + int RETURN = 100; | |
| 476 | + int TRY = 101; | |
| 477 | + int CATCH = 102; | |
| 478 | + int FINALLY = 103; | |
| 479 | + int THROW = 104; | |
| 480 | + int STAT = 105; | |
| 481 | + int EXPRESSION = 106; | |
| 482 | + int DECLARATION = 107; | |
| 483 | + int VARDECLARATION = 108; | |
| 484 | + | |
| 485 | + /* | |
| 486 | + * Declaration keywords | |
| 487 | + */ | |
| 488 | + int IMPORT = 110; | |
| 489 | + int CLASS = 111; | |
| 490 | + int EXTENDS = 112; | |
| 491 | + int IMPLEMENTS = 113; | |
| 492 | + int INTERFACE = 114; | |
| 493 | + int PACKAGE = 115; | |
| 494 | + | |
| 495 | + /* | |
| 496 | + * Modifier keywords | |
| 497 | + */ | |
| 498 | + int PRIVATE = 120; | |
| 499 | + int PUBLIC = 121; | |
| 500 | + int PROTECTED = 122; | |
| 501 | + int CONST = 123; | |
| 502 | + int STATIC = 124; | |
| 503 | + int TRANSIENT = 125; | |
| 504 | + int SYNCHRONIZED = 126; | |
| 505 | + int NATIVE = 127; | |
| 506 | + int FINAL = 128; | |
| 507 | + int VOLATILE = 129; | |
| 508 | + int ABSTRACT = 130; | |
| 509 | + int STRICTFP = 131; | |
| 510 | + | |
| 511 | + /* | |
| 512 | + * Punctuation | |
| 513 | + */ | |
| 514 | + int SEMICOLON = 135; | |
| 515 | + int COLON = 136; | |
| 516 | + int QUESTIONMARK = 137; | |
| 517 | + int LBRACE = 138; | |
| 518 | + int RBRACE = 139; | |
| 519 | + int LPAREN = 140; | |
| 520 | + int RPAREN = 141; | |
| 521 | + int LSQBRACKET = 142; | |
| 522 | + int RSQBRACKET = 143; | |
| 523 | + int THROWS = 144; | |
| 524 | + | |
| 525 | + /* | |
| 526 | + * Special tokens | |
| 527 | + */ | |
| 528 | + int ERROR = 145; // an error | |
| 529 | + int COMMENT = 146; // not used anymore. | |
| 530 | + int TYPE = 147; | |
| 531 | + int LENGTH = 148; | |
| 532 | + int INLINERETURN = 149; | |
| 533 | + int INLINEMETHOD = 150; | |
| 534 | + int INLINENEWINSTANCE = 151; | |
| 535 | + | |
| 536 | + /* | |
| 537 | + * Operator precedence | |
| 538 | + */ | |
| 539 | + int opPrecedence[] = { | |
| 540 | + 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, | |
| 541 | + 11, 11, 11, 12, 13, 14, 15, 16, 17, 18, | |
| 542 | + 18, 19, 19, 19, 19, 19, 20, 20, 20, 21, | |
| 543 | + 21, 22, 22, 22, 23, 24, 24, 24, 24, 24, | |
| 544 | + 24, 25, 25, 26, 26, 26, 26, 26, 26 | |
| 545 | + }; | |
| 546 | + | |
| 547 | + /* | |
| 548 | + * Operator names | |
| 549 | + */ | |
| 550 | + String opNames[] = { | |
| 551 | + ",", "=", "*=", "/=", "%=", | |
| 552 | + "+=", "-=", "<<=", ">>=", ">>>=", | |
| 553 | + "&=", "|=", "^=", "?:", "||", | |
| 554 | + "&&", "|", "^", "&", "!=", | |
| 555 | + "==", ">=", ">", "<=", "<", | |
| 556 | + "instanceof", "<<", ">>", ">>>", "+", | |
| 557 | + "-", "/", "%", "*", "cast", | |
| 558 | + "+", "-", "!", "~", "++", | |
| 559 | + "--", "new", "new", "new", "++", | |
| 560 | + "--", "field","method","[]", "new", | |
| 561 | + "++", "--", null, null, null, | |
| 562 | + | |
| 563 | + "convert", "expr", "array", "goto", null, | |
| 564 | + | |
| 565 | + "Identifier", "boolean", "byte", "char", "short", | |
| 566 | + "int", "long", "float", "double", "string", | |
| 567 | + | |
| 568 | + "byte", "char", "short", "int", "long", | |
| 569 | + "float", "double", "void", "boolean", null, | |
| 570 | + | |
| 571 | + "true", "false", "this", "super", "null", | |
| 572 | + null, null, null, null, null, | |
| 573 | + | |
| 574 | + "if", "else", "for", "while","do", | |
| 575 | + "switch", "case", "default", "break", "continue", | |
| 576 | + "return", "try", "catch", "finally", "throw", | |
| 577 | + "stat", "expression", "declaration", "declaration", null, | |
| 578 | + | |
| 579 | + "import", "class", "extends", "implements", "interface", | |
| 580 | + "package", null, null, null, null, | |
| 581 | + | |
| 582 | + "private", "public", "protected", "const", "static", | |
| 583 | + "transient", "synchronized", "native", "final", "volatile", | |
| 584 | + "abstract", "strictfp", null, null, null, | |
| 585 | + | |
| 586 | + ";", ":", "?", "{", "}", | |
| 587 | + "(", ")", "[", "]", "throws", | |
| 588 | + "error", "comment", "type", "length", "inline-return", | |
| 589 | + "inline-method", "inline-new" | |
| 590 | + }; | |
| 591 | +} | |
| @@ -0,0 +1,998 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +import java.util.Stack; | |
| 29 | +import java.io.IOException; | |
| 30 | +import sun.tools.tree.Context; | |
| 31 | +//JCOV | |
| 32 | +import java.io.File; | |
| 33 | +//end JCOV | |
| 34 | + | |
| 35 | +/** | |
| 36 | + * This class defines the environment for a compilation. | |
| 37 | + * It is used to load classes, resolve class names and | |
| 38 | + * report errors. It is an abstract class, a subclass | |
| 39 | + * must define implementations for some of the functions.<p> | |
| 40 | + * | |
| 41 | + * An environment has a source object associated with it. | |
| 42 | + * This is the thing against which errors are reported, it | |
| 43 | + * is usually a file name, a field or a class.<p> | |
| 44 | + * | |
| 45 | + * Environments can be nested to change the source object.<p> | |
| 46 | + * | |
| 47 | + * WARNING: The contents of this source file are not part of any | |
| 48 | + * supported API. Code that depends on them does so at its own risk: | |
| 49 | + * they are subject to change or removal without notice. | |
| 50 | + * | |
| 51 | + * @author Arthur van Hoff | |
| 52 | + */ | |
| 53 | + | |
| 54 | +public class Environment implements Constants { | |
| 55 | + /** | |
| 56 | + * The actual environment to which everything is forwarded. | |
| 57 | + */ | |
| 58 | + Environment env; | |
| 59 | + | |
| 60 | + /** | |
| 61 | + * External character encoding name | |
| 62 | + */ | |
| 63 | + String encoding; | |
| 64 | + | |
| 65 | + /** | |
| 66 | + * The object that is currently being parsed/compiled. | |
| 67 | + * It is either a file name (String) or a field (MemberDefinition) | |
| 68 | + * or a class (ClassDeclaration or ClassDefinition). | |
| 69 | + */ | |
| 70 | + Object source; | |
| 71 | + | |
| 72 | + public Environment(Environment env, Object source) { | |
| 73 | + if (env != null && env.env != null && env.getClass() == this.getClass()) | |
| 74 | + env = env.env; // a small optimization | |
| 75 | + this.env = env; | |
| 76 | + this.source = source; | |
| 77 | + } | |
| 78 | + public Environment() { | |
| 79 | + this(null, null); | |
| 80 | + } | |
| 81 | + | |
| 82 | + /** | |
| 83 | + * Tells whether an Identifier refers to a package which should be | |
| 84 | + * exempt from the "exists" check in Imports#resolve(). | |
| 85 | + */ | |
| 86 | + public boolean isExemptPackage(Identifier id) { | |
| 87 | + return env.isExemptPackage(id); | |
| 88 | + } | |
| 89 | + | |
| 90 | + /** | |
| 91 | + * Return a class declaration given a fully qualified class name. | |
| 92 | + */ | |
| 93 | + public ClassDeclaration getClassDeclaration(Identifier nm) { | |
| 94 | + return env.getClassDeclaration(nm); | |
| 95 | + } | |
| 96 | + | |
| 97 | + /** | |
| 98 | + * Return a class definition given a fully qualified class name. | |
| 99 | + * <p> | |
| 100 | + * Should be called only with 'internal' class names, i.e., the result | |
| 101 | + * of a call to 'resolveName' or a synthetic class name. | |
| 102 | + */ | |
| 103 | + public final ClassDefinition getClassDefinition(Identifier nm) throws ClassNotFound { | |
| 104 | + if (nm.isInner()) { | |
| 105 | + ClassDefinition c = getClassDefinition(nm.getTopName()); | |
| 106 | + Identifier tail = nm.getFlatName(); | |
| 107 | + walkTail: | |
| 108 | + while (tail.isQualified()) { | |
| 109 | + tail = tail.getTail(); | |
| 110 | + Identifier head = tail.getHead(); | |
| 111 | + //System.out.println("CLASS: " + c + " HEAD: " + head + " TAIL: " + tail); | |
| 112 | + String hname = head.toString(); | |
| 113 | + // If the name is of the form 'ClassName.N$localName', where N is | |
| 114 | + // a number, the field 'N$localName' may not necessarily be a member | |
| 115 | + // of the class named by 'ClassName', but might be a member of some | |
| 116 | + // inaccessible class contained within it. We use 'getLocalClass' | |
| 117 | + // to do the lookup in this case. This is part of a fix for bugid | |
| 118 | + // 4054523 and 4030421. See also 'BatchEnvironment.makeClassDefinition'. | |
| 119 | + // This should also work for anonymous class names of the form | |
| 120 | + // 'ClassName.N'. Note that the '.' qualifications get converted to | |
| 121 | + // '$' characters when determining the external name of the class and | |
| 122 | + // the name of the class file. | |
| 123 | + if (hname.length() > 0 | |
| 124 | + && Character.isDigit(hname.charAt(0))) { | |
| 125 | + ClassDefinition localClass = c.getLocalClass(hname); | |
| 126 | + if (localClass != null) { | |
| 127 | + c = localClass; | |
| 128 | + continue walkTail; | |
| 129 | + } | |
| 130 | + } else { | |
| 131 | + for (MemberDefinition f = c.getFirstMatch(head); | |
| 132 | + f != null; f = f.getNextMatch()) { | |
| 133 | + if (f.isInnerClass()) { | |
| 134 | + c = f.getInnerClass(); | |
| 135 | + continue walkTail; | |
| 136 | + } | |
| 137 | + } | |
| 138 | + } | |
| 139 | + throw new ClassNotFound(Identifier.lookupInner(c.getName(), head)); | |
| 140 | + } | |
| 141 | + //System.out.println("FOUND " + c + " FOR " + nm); | |
| 142 | + return c; | |
| 143 | + } | |
| 144 | + return getClassDeclaration(nm).getClassDefinition(this); | |
| 145 | + } | |
| 146 | + | |
| 147 | + | |
| 148 | + /** | |
| 149 | + * Return a class declaration given a type. Only works for | |
| 150 | + * class types. | |
| 151 | + */ | |
| 152 | + public ClassDeclaration getClassDeclaration(Type t) { | |
| 153 | + return getClassDeclaration(t.getClassName()); | |
| 154 | + } | |
| 155 | + | |
| 156 | + /** | |
| 157 | + * Return a class definition given a type. Only works for | |
| 158 | + * class types. | |
| 159 | + */ | |
| 160 | + public final ClassDefinition getClassDefinition(Type t) throws ClassNotFound { | |
| 161 | + return getClassDefinition(t.getClassName()); | |
| 162 | + } | |
| 163 | + | |
| 164 | + /** | |
| 165 | + * Check if a class exists (without actually loading it). | |
| 166 | + * (Since inner classes cannot in general be examined without | |
| 167 | + * loading source, this method does not accept inner names.) | |
| 168 | + */ | |
| 169 | + public boolean classExists(Identifier nm) { | |
| 170 | + return env.classExists(nm); | |
| 171 | + } | |
| 172 | + | |
| 173 | + public final boolean classExists(Type t) { | |
| 174 | + return !t.isType(TC_CLASS) || classExists(t.getClassName()); | |
| 175 | + } | |
| 176 | + | |
| 177 | + /** | |
| 178 | + * Get the package path for a package | |
| 179 | + */ | |
| 180 | + public Package getPackage(Identifier pkg) throws IOException { | |
| 181 | + return env.getPackage(pkg); | |
| 182 | + } | |
| 183 | + | |
| 184 | + /** | |
| 185 | + * Load the definition of a class. | |
| 186 | + */ | |
| 187 | + public void loadDefinition(ClassDeclaration c) { | |
| 188 | + env.loadDefinition(c); | |
| 189 | + } | |
| 190 | + | |
| 191 | + /** | |
| 192 | + * Return the source of the environment (ie: the thing being compiled/parsed). | |
| 193 | + */ | |
| 194 | + public final Object getSource() { | |
| 195 | + return source; | |
| 196 | + } | |
| 197 | + | |
| 198 | + /** | |
| 199 | + * Resolve a type. Make sure that all the classes referred to by | |
| 200 | + * the type have a definition. Report errors. Return true if | |
| 201 | + * the type is well-formed. Presently used for types appearing | |
| 202 | + * in member declarations, which represent named types internally as | |
| 203 | + * qualified identifiers. Type names appearing in local variable | |
| 204 | + * declarations and within expressions are represented as identifier | |
| 205 | + * or field expressions, and are resolved by 'toType', which delegates | |
| 206 | + * handling of the non-inner portion of the name to this method. | |
| 207 | + * <p> | |
| 208 | + * In 'toType', the various stages of qualification are represented by | |
| 209 | + * separate AST nodes. Here, we are given a single identifier which | |
| 210 | + * contains the entire qualification structure. It is not possible in | |
| 211 | + * general to set the error location to the exact position of a component | |
| 212 | + * that is in error, so an error message must refer to the entire qualified | |
| 213 | + * name. An attempt to keep track of the string length of the components of | |
| 214 | + * the name and to offset the location accordingly fails because the initial | |
| 215 | + * prefix of the name may have been rewritten by an earlier call to | |
| 216 | + * 'resolveName'. See 'SourceMember.resolveTypeStructure'. The situation | |
| 217 | + * is actually even worse than this, because only a single location is | |
| 218 | + * passed in for an entire declaration, which may contain many type names. | |
| 219 | + * All error messages are thus poorly localized. These checks should be | |
| 220 | + * done while traversing the parse tree for the type, not the type descriptor. | |
| 221 | + * <p> | |
| 222 | + * DESIGN NOTE: | |
| 223 | + * As far as I can tell, the two-stage resolution of names represented in | |
| 224 | + * string form is an artifact of the late implementation of inner classes | |
| 225 | + * and the use of mangled names internally within the compiler. All | |
| 226 | + * qualified names should have their hiearchical structure made explicit | |
| 227 | + * in the parse tree at the phase at which they are presented for static | |
| 228 | + * semantic checking. This would affect class names appearing in 'extends', | |
| 229 | + * 'implements', and 'throws' clauses, as well as in member declarations. | |
| 230 | + */ | |
| 231 | + public boolean resolve(long where, ClassDefinition c, Type t) { | |
| 232 | + switch (t.getTypeCode()) { | |
| 233 | + case TC_CLASS: { | |
| 234 | + ClassDefinition def; | |
| 235 | + try { | |
| 236 | + Identifier nm = t.getClassName(); | |
| 237 | + if (!nm.isQualified() && !nm.isInner() && !classExists(nm)) { | |
| 238 | + resolve(nm); // elicit complaints about ambiguity | |
| 239 | + } | |
| 240 | + def = getQualifiedClassDefinition(where, nm, c, false); | |
| 241 | + if (!c.canAccess(this, def.getClassDeclaration())) { | |
| 242 | + // Reported error location may be imprecise | |
| 243 | + // if the name is qualified. | |
| 244 | + error(where, "cant.access.class", def); | |
| 245 | + return true; // return false later | |
| 246 | + } | |
| 247 | + def.noteUsedBy(c, where, env); | |
| 248 | + } catch (AmbiguousClass ee) { | |
| 249 | + error(where, "ambig.class", ee.name1, ee.name2); | |
| 250 | + return false; | |
| 251 | + } catch (ClassNotFound e) { | |
| 252 | + // For now, report "class.and.package" only when the code | |
| 253 | + // is going to fail anyway. | |
| 254 | + try { | |
| 255 | + if (e.name.isInner() && | |
| 256 | + getPackage(e.name.getTopName()).exists()) { | |
| 257 | + env.error(where, "class.and.package", | |
| 258 | + e.name.getTopName()); | |
| 259 | + } | |
| 260 | + } catch (IOException ee) { | |
| 261 | + env.error(where, "io.exception", "package check"); | |
| 262 | + } | |
| 263 | + // This error message is also emitted for 'new' expressions. | |
| 264 | + // error(where, "class.not.found", e.name, "declaration"); | |
| 265 | + error(where, "class.not.found.no.context", e.name); | |
| 266 | + return false; | |
| 267 | + } | |
| 268 | + return true; | |
| 269 | + } | |
| 270 | + | |
| 271 | + case TC_ARRAY: | |
| 272 | + return resolve(where, c, t.getElementType()); | |
| 273 | + | |
| 274 | + case TC_METHOD: | |
| 275 | + boolean ok = resolve(where, c, t.getReturnType()); | |
| 276 | + Type args[] = t.getArgumentTypes(); | |
| 277 | + for (int i = args.length ; i-- > 0 ; ) { | |
| 278 | + ok &= resolve(where, c, args[i]); | |
| 279 | + } | |
| 280 | + return ok; | |
| 281 | + } | |
| 282 | + return true; | |
| 283 | + } | |
| 284 | + | |
| 285 | + /** | |
| 286 | + * Given its fully-qualified name, verify that a class is defined and accessible. | |
| 287 | + * Used to check components of qualified names in contexts where a class is expected. | |
| 288 | + * Like 'resolve', but is given a single type name, not a type descriptor. | |
| 289 | + */ | |
| 290 | + public boolean resolveByName(long where, ClassDefinition c, Identifier nm) { | |
| 291 | + return resolveByName(where, c, nm, false); | |
| 292 | + } | |
| 293 | + | |
| 294 | + public boolean resolveExtendsByName(long where, ClassDefinition c, Identifier nm) { | |
| 295 | + return resolveByName(where, c, nm, true); | |
| 296 | + } | |
| 297 | + | |
| 298 | + private boolean resolveByName(long where, ClassDefinition c, | |
| 299 | + Identifier nm, boolean isExtends) { | |
| 300 | + ClassDefinition def; | |
| 301 | + try { | |
| 302 | + if (!nm.isQualified() && !nm.isInner() && !classExists(nm)) { | |
| 303 | + resolve(nm); // elicit complaints about ambiguity | |
| 304 | + } | |
| 305 | + def = getQualifiedClassDefinition(where, nm, c, isExtends); | |
| 306 | + ClassDeclaration decl = def.getClassDeclaration(); | |
| 307 | + if (!((!isExtends && c.canAccess(this, decl)) | |
| 308 | + || | |
| 309 | + (isExtends && c.extendsCanAccess(this, decl)))) { | |
| 310 | + error(where, "cant.access.class", def); | |
| 311 | + return true; // return false later | |
| 312 | + } | |
| 313 | + } catch (AmbiguousClass ee) { | |
| 314 | + error(where, "ambig.class", ee.name1, ee.name2); | |
| 315 | + return false; | |
| 316 | + } catch (ClassNotFound e) { | |
| 317 | + // For now, report "class.and.package" only when the code | |
| 318 | + // is going to fail anyway. | |
| 319 | + try { | |
| 320 | + if (e.name.isInner() && | |
| 321 | + getPackage(e.name.getTopName()).exists()) { | |
| 322 | + env.error(where, "class.and.package", | |
| 323 | + e.name.getTopName()); | |
| 324 | + } | |
| 325 | + } catch (IOException ee) { | |
| 326 | + env.error(where, "io.exception", "package check"); | |
| 327 | + } | |
| 328 | + error(where, "class.not.found", e.name, "type name"); | |
| 329 | + return false; | |
| 330 | + } | |
| 331 | + return true; | |
| 332 | + } | |
| 333 | + | |
| 334 | + /** | |
| 335 | + * Like 'getClassDefinition(env)', but check access on each component. | |
| 336 | + * Currently called only by 'resolve' above. It is doubtful that calls | |
| 337 | + * to 'getClassDefinition(env)' are appropriate now. | |
| 338 | + */ | |
| 339 | + public final ClassDefinition | |
| 340 | + getQualifiedClassDefinition(long where, | |
| 341 | + Identifier nm, | |
| 342 | + ClassDefinition ctxClass, | |
| 343 | + boolean isExtends) throws ClassNotFound { | |
| 344 | + if (nm.isInner()) { | |
| 345 | + ClassDefinition c = getClassDefinition(nm.getTopName()); | |
| 346 | + Identifier tail = nm.getFlatName(); | |
| 347 | + walkTail: | |
| 348 | + while (tail.isQualified()) { | |
| 349 | + tail = tail.getTail(); | |
| 350 | + Identifier head = tail.getHead(); | |
| 351 | + // System.out.println("CLASS: " + c + " HEAD: " + head + " TAIL: " + tail); | |
| 352 | + String hname = head.toString(); | |
| 353 | + // Handle synthesized names of local and anonymous classes. | |
| 354 | + // See 'getClassDefinition(env)' above. | |
| 355 | + if (hname.length() > 0 | |
| 356 | + && Character.isDigit(hname.charAt(0))) { | |
| 357 | + ClassDefinition localClass = c.getLocalClass(hname); | |
| 358 | + if (localClass != null) { | |
| 359 | + c = localClass; | |
| 360 | + continue walkTail; | |
| 361 | + } | |
| 362 | + } else { | |
| 363 | + for (MemberDefinition f = c.getFirstMatch(head); | |
| 364 | + f != null; f = f.getNextMatch()) { | |
| 365 | + if (f.isInnerClass()) { | |
| 366 | + ClassDeclaration rdecl = c.getClassDeclaration(); | |
| 367 | + c = f.getInnerClass(); | |
| 368 | + ClassDeclaration fdecl = c.getClassDeclaration(); | |
| 369 | + // This check is presumably applicable even if the | |
| 370 | + // original source-code name (expanded by 'resolveNames') | |
| 371 | + // was a simple, unqualified name. Hopefully, JLS 2e | |
| 372 | + // will clarify the matter. | |
| 373 | + if ((!isExtends | |
| 374 | + && !ctxClass.canAccess(env, fdecl)) | |
| 375 | + || | |
| 376 | + (isExtends | |
| 377 | + && !ctxClass.extendsCanAccess(env, fdecl))) { | |
| 378 | + // Reported error location is imprecise. | |
| 379 | + env.error(where, "no.type.access", head, rdecl, ctxClass); | |
| 380 | + } | |
| 381 | + // The JLS 6.6.2 restrictions on access to protected members | |
| 382 | + // depend in an essential way upon the syntactic form of the name. | |
| 383 | + // Since the compiler has previously expanded the class names | |
| 384 | + // here into fully-qualified form ('resolveNames'), this check | |
| 385 | + // cannot be performed here. Unfortunately, the original names | |
| 386 | + // are clobbered during 'basicCheck', which is also the phase that | |
| 387 | + // resolves the inheritance structure, required to implement the | |
| 388 | + // access restrictions. Pending a large-scale revision of the | |
| 389 | + // name-resolution machinery, we forgo this check, with the result | |
| 390 | + // that the JLS 6.6.2 restrictions are not enforced for some cases | |
| 391 | + // of qualified access to inner classes. Some qualified names are | |
| 392 | + // resolved elsewhere via a different mechanism, and will be | |
| 393 | + // treated correctly -- see 'FieldExpression.checkCommon'. | |
| 394 | + /*---------------------------------------* | |
| 395 | + if (f.isProtected()) { | |
| 396 | + Type rty = Type.tClass(rdecl.getName()); // hack | |
| 397 | + if (!ctxClass.protectedAccess(env, f, rty)) { | |
| 398 | + // Reported error location is imprecise. | |
| 399 | + env.error(where, "invalid.protected.type.use", | |
| 400 | + head, ctxClass, rty); | |
| 401 | + } | |
| 402 | + } | |
| 403 | + *---------------------------------------*/ | |
| 404 | + continue walkTail; | |
| 405 | + } | |
| 406 | + } | |
| 407 | + } | |
| 408 | + throw new ClassNotFound(Identifier.lookupInner(c.getName(), head)); | |
| 409 | + } | |
| 410 | + //System.out.println("FOUND " + c + " FOR " + nm); | |
| 411 | + return c; | |
| 412 | + } | |
| 413 | + return getClassDeclaration(nm).getClassDefinition(this); | |
| 414 | + } | |
| 415 | + | |
| 416 | + /** | |
| 417 | + * Resolve the names within a type, returning the adjusted type. | |
| 418 | + * Adjust class names to reflect scoping. | |
| 419 | + * Do not report errors. | |
| 420 | + * <p> | |
| 421 | + * NOTE: It would be convenient to check for errors here, such as | |
| 422 | + * verifying that each component of a qualified name exists and is | |
| 423 | + * accessible. Why must this be done in a separate phase? | |
| 424 | + * <p> | |
| 425 | + * If the 'synth' argument is true, indicating that the member whose | |
| 426 | + * type is being resolved is synthetic, names are resolved with respect | |
| 427 | + * to the package scope. (Fix for 4097882) | |
| 428 | + */ | |
| 429 | + public Type resolveNames(ClassDefinition c, Type t, boolean synth) { | |
| 430 | + if (tracing) dtEvent("Environment.resolveNames: " + c + ", " + t); | |
| 431 | + switch (t.getTypeCode()) { | |
| 432 | + case TC_CLASS: { | |
| 433 | + Identifier name = t.getClassName(); | |
| 434 | + Identifier rname; | |
| 435 | + if (synth) { | |
| 436 | + rname = resolvePackageQualifiedName(name); | |
| 437 | + } else { | |
| 438 | + rname = c.resolveName(this, name); | |
| 439 | + } | |
| 440 | + if (name != rname) { | |
| 441 | + t = Type.tClass(rname); | |
| 442 | + } | |
| 443 | + break; | |
| 444 | + } | |
| 445 | + | |
| 446 | + case TC_ARRAY: | |
| 447 | + t = Type.tArray(resolveNames(c, t.getElementType(), synth)); | |
| 448 | + break; | |
| 449 | + | |
| 450 | + case TC_METHOD: { | |
| 451 | + Type ret = t.getReturnType(); | |
| 452 | + Type rret = resolveNames(c, ret, synth); | |
| 453 | + Type args[] = t.getArgumentTypes(); | |
| 454 | + Type rargs[] = new Type[args.length]; | |
| 455 | + boolean changed = (ret != rret); | |
| 456 | + for (int i = args.length ; i-- > 0 ; ) { | |
| 457 | + Type arg = args[i]; | |
| 458 | + Type rarg = resolveNames(c, arg, synth); | |
| 459 | + rargs[i] = rarg; | |
| 460 | + if (arg != rarg) { | |
| 461 | + changed = true; | |
| 462 | + } | |
| 463 | + } | |
| 464 | + if (changed) { | |
| 465 | + t = Type.tMethod(rret, rargs); | |
| 466 | + } | |
| 467 | + break; | |
| 468 | + } | |
| 469 | + } | |
| 470 | + return t; | |
| 471 | + } | |
| 472 | + | |
| 473 | + /** | |
| 474 | + * Resolve a class name, using only package and import directives. | |
| 475 | + * Report no errors. | |
| 476 | + * <p> | |
| 477 | + */ | |
| 478 | + public Identifier resolveName(Identifier name) { | |
| 479 | + // This logic is pretty exactly parallel to that of | |
| 480 | + // ClassDefinition.resolveName(). | |
| 481 | + if (name.isQualified()) { | |
| 482 | + // Try to resolve the first identifier component, | |
| 483 | + // because inner class names take precedence over | |
| 484 | + // package prefixes. (Cf. ClassDefinition.resolveName.) | |
| 485 | + Identifier rhead = resolveName(name.getHead()); | |
| 486 | + | |
| 487 | + if (rhead.hasAmbigPrefix()) { | |
| 488 | + // The first identifier component refers to an | |
| 489 | + // ambiguous class. Limp on. We throw away the | |
| 490 | + // rest of the classname as it is irrelevant. | |
| 491 | + // (part of solution for 4059855). | |
| 492 | + return rhead; | |
| 493 | + } | |
| 494 | + | |
| 495 | + if (!this.classExists(rhead)) { | |
| 496 | + return this.resolvePackageQualifiedName(name); | |
| 497 | + } | |
| 498 | + try { | |
| 499 | + return this.getClassDefinition(rhead). | |
| 500 | + resolveInnerClass(this, name.getTail()); | |
| 501 | + } catch (ClassNotFound ee) { | |
| 502 | + // return partially-resolved name someone else can fail on | |
| 503 | + return Identifier.lookupInner(rhead, name.getTail()); | |
| 504 | + } | |
| 505 | + } | |
| 506 | + try { | |
| 507 | + return resolve(name); | |
| 508 | + } catch (AmbiguousClass ee) { | |
| 509 | + // Don't force a resolution of the name if it is ambiguous. | |
| 510 | + // Forcing the resolution would tack the current package | |
| 511 | + // name onto the front of the class, which would be wrong. | |
| 512 | + // Instead, mark the name as ambiguous and let a later stage | |
| 513 | + // find the error by calling env.resolve(name). | |
| 514 | + // (part of solution for 4059855). | |
| 515 | + | |
| 516 | + if (name.hasAmbigPrefix()) { | |
| 517 | + return name; | |
| 518 | + } else { | |
| 519 | + return name.addAmbigPrefix(); | |
| 520 | + } | |
| 521 | + } catch (ClassNotFound ee) { | |
| 522 | + // last chance to make something halfway sensible | |
| 523 | + Imports imports = getImports(); | |
| 524 | + if (imports != null) | |
| 525 | + return imports.forceResolve(this, name); | |
| 526 | + } | |
| 527 | + return name; | |
| 528 | + } | |
| 529 | + | |
| 530 | + /** | |
| 531 | + * Discover if name consists of a package prefix, followed by the | |
| 532 | + * name of a class (that actually exists), followed possibly by | |
| 533 | + * some inner class names. If we can't find a class that exists, | |
| 534 | + * return the name unchanged. | |
| 535 | + * <p> | |
| 536 | + * This routine is used after a class name fails to | |
| 537 | + * be resolved by means of imports or inner classes. | |
| 538 | + * However, import processing uses this routine directly, | |
| 539 | + * since import names must be exactly qualified to start with. | |
| 540 | + */ | |
| 541 | + public final Identifier resolvePackageQualifiedName(Identifier name) { | |
| 542 | + Identifier tail = null; | |
| 543 | + for (;;) { | |
| 544 | + if (classExists(name)) { | |
| 545 | + break; | |
| 546 | + } | |
| 547 | + if (!name.isQualified()) { | |
| 548 | + name = (tail == null) ? name : Identifier.lookup(name, tail); | |
| 549 | + tail = null; | |
| 550 | + break; | |
| 551 | + } | |
| 552 | + Identifier nm = name.getName(); | |
| 553 | + tail = (tail == null)? nm: Identifier.lookup(nm, tail); | |
| 554 | + name = name.getQualifier(); | |
| 555 | + } | |
| 556 | + if (tail != null) | |
| 557 | + name = Identifier.lookupInner(name, tail); | |
| 558 | + return name; | |
| 559 | + } | |
| 560 | + | |
| 561 | + /** | |
| 562 | + * Resolve a class name, using only package and import directives. | |
| 563 | + */ | |
| 564 | + public Identifier resolve(Identifier nm) throws ClassNotFound { | |
| 565 | + if (env == null) return nm; // a pretty useless no-op | |
| 566 | + return env.resolve(nm); | |
| 567 | + } | |
| 568 | + | |
| 569 | + /** | |
| 570 | + * Get the imports used to resolve class names. | |
| 571 | + */ | |
| 572 | + public Imports getImports() { | |
| 573 | + if (env == null) return null; // lame default | |
| 574 | + return env.getImports(); | |
| 575 | + } | |
| 576 | + | |
| 577 | + /** | |
| 578 | + * Create a new class. | |
| 579 | + */ | |
| 580 | + public ClassDefinition makeClassDefinition(Environment origEnv, long where, | |
| 581 | + IdentifierToken name, | |
| 582 | + String doc, int modifiers, | |
| 583 | + IdentifierToken superClass, | |
| 584 | + IdentifierToken interfaces[], | |
| 585 | + ClassDefinition outerClass) { | |
| 586 | + if (env == null) return null; // lame default | |
| 587 | + return env.makeClassDefinition(origEnv, where, name, | |
| 588 | + doc, modifiers, | |
| 589 | + superClass, interfaces, outerClass); | |
| 590 | + } | |
| 591 | + | |
| 592 | + /** | |
| 593 | + * Create a new field. | |
| 594 | + */ | |
| 595 | + public MemberDefinition makeMemberDefinition(Environment origEnv, long where, | |
| 596 | + ClassDefinition clazz, | |
| 597 | + String doc, int modifiers, | |
| 598 | + Type type, Identifier name, | |
| 599 | + IdentifierToken argNames[], | |
| 600 | + IdentifierToken expIds[], | |
| 601 | + Object value) { | |
| 602 | + if (env == null) return null; // lame default | |
| 603 | + return env.makeMemberDefinition(origEnv, where, clazz, doc, modifiers, | |
| 604 | + type, name, argNames, expIds, value); | |
| 605 | + } | |
| 606 | + | |
| 607 | + /** | |
| 608 | + * Returns true if the given method is applicable to the given arguments | |
| 609 | + */ | |
| 610 | + | |
| 611 | + public boolean isApplicable(MemberDefinition m, Type args[]) throws ClassNotFound { | |
| 612 | + Type mType = m.getType(); | |
| 613 | + if (!mType.isType(TC_METHOD)) | |
| 614 | + return false; | |
| 615 | + Type mArgs[] = mType.getArgumentTypes(); | |
| 616 | + if (args.length != mArgs.length) | |
| 617 | + return false; | |
| 618 | + for (int i = args.length ; --i >= 0 ;) | |
| 619 | + if (!isMoreSpecific(args[i], mArgs[i])) | |
| 620 | + return false; | |
| 621 | + return true; | |
| 622 | + } | |
| 623 | + | |
| 624 | + | |
| 625 | + /** | |
| 626 | + * Returns true if "best" is in every argument at least as good as "other" | |
| 627 | + */ | |
| 628 | + public boolean isMoreSpecific(MemberDefinition best, MemberDefinition other) | |
| 629 | + throws ClassNotFound { | |
| 630 | + Type bestType = best.getClassDeclaration().getType(); | |
| 631 | + Type otherType = other.getClassDeclaration().getType(); | |
| 632 | + boolean result = isMoreSpecific(bestType, otherType) | |
| 633 | + && isApplicable(other, best.getType().getArgumentTypes()); | |
| 634 | + // System.out.println("isMoreSpecific: " + best + "/" + other | |
| 635 | + // + " => " + result); | |
| 636 | + return result; | |
| 637 | + } | |
| 638 | + | |
| 639 | + /** | |
| 640 | + * Returns true if "from" is a more specific type than "to" | |
| 641 | + */ | |
| 642 | + | |
| 643 | + public boolean isMoreSpecific(Type from, Type to) throws ClassNotFound { | |
| 644 | + return implicitCast(from, to); | |
| 645 | + } | |
| 646 | + | |
| 647 | + /** | |
| 648 | + * Return true if an implicit cast from this type to | |
| 649 | + * the given type is allowed. | |
| 650 | + */ | |
| 651 | + public boolean implicitCast(Type from, Type to) throws ClassNotFound { | |
| 652 | + if (from == to) | |
| 653 | + return true; | |
| 654 | + | |
| 655 | + int toTypeCode = to.getTypeCode(); | |
| 656 | + | |
| 657 | + switch(from.getTypeCode()) { | |
| 658 | + case TC_BYTE: | |
| 659 | + if (toTypeCode == TC_SHORT) | |
| 660 | + return true; | |
| 661 | + case TC_SHORT: | |
| 662 | + case TC_CHAR: | |
| 663 | + if (toTypeCode == TC_INT) return true; | |
| 664 | + case TC_INT: | |
| 665 | + if (toTypeCode == TC_LONG) return true; | |
| 666 | + case TC_LONG: | |
| 667 | + if (toTypeCode == TC_FLOAT) return true; | |
| 668 | + case TC_FLOAT: | |
| 669 | + if (toTypeCode == TC_DOUBLE) return true; | |
| 670 | + case TC_DOUBLE: | |
| 671 | + default: | |
| 672 | + return false; | |
| 673 | + | |
| 674 | + case TC_NULL: | |
| 675 | + return to.inMask(TM_REFERENCE); | |
| 676 | + | |
| 677 | + case TC_ARRAY: | |
| 678 | + if (!to.isType(TC_ARRAY)) { | |
| 679 | + return (to == Type.tObject || to == Type.tCloneable | |
| 680 | + || to == Type.tSerializable); | |
| 681 | + } else { | |
| 682 | + // both are arrays. recurse down both until one isn't an array | |
| 683 | + do { | |
| 684 | + from = from.getElementType(); | |
| 685 | + to = to.getElementType(); | |
| 686 | + } while (from.isType(TC_ARRAY) && to.isType(TC_ARRAY)); | |
| 687 | + if ( from.inMask(TM_ARRAY|TM_CLASS) | |
| 688 | + && to.inMask(TM_ARRAY|TM_CLASS)) { | |
| 689 | + return isMoreSpecific(from, to); | |
| 690 | + } else { | |
| 691 | + return (from.getTypeCode() == to.getTypeCode()); | |
| 692 | + } | |
| 693 | + } | |
| 694 | + | |
| 695 | + case TC_CLASS: | |
| 696 | + if (toTypeCode == TC_CLASS) { | |
| 697 | + ClassDefinition fromDef = getClassDefinition(from); | |
| 698 | + ClassDefinition toDef = getClassDefinition(to); | |
| 699 | + return toDef.implementedBy(this, | |
| 700 | + fromDef.getClassDeclaration()); | |
| 701 | + } else { | |
| 702 | + return false; | |
| 703 | + } | |
| 704 | + } | |
| 705 | + } | |
| 706 | + | |
| 707 | + | |
| 708 | + /** | |
| 709 | + * Return true if an explicit cast from this type to | |
| 710 | + * the given type is allowed. | |
| 711 | + */ | |
| 712 | + public boolean explicitCast(Type from, Type to) throws ClassNotFound { | |
| 713 | + if (implicitCast(from, to)) { | |
| 714 | + return true; | |
| 715 | + } | |
| 716 | + if (from.inMask(TM_NUMBER)) { | |
| 717 | + return to.inMask(TM_NUMBER); | |
| 718 | + } | |
| 719 | + if (from.isType(TC_CLASS) && to.isType(TC_CLASS)) { | |
| 720 | + ClassDefinition fromClass = getClassDefinition(from); | |
| 721 | + ClassDefinition toClass = getClassDefinition(to); | |
| 722 | + if (toClass.isFinal()) { | |
| 723 | + return fromClass.implementedBy(this, | |
| 724 | + toClass.getClassDeclaration()); | |
| 725 | + } | |
| 726 | + if (fromClass.isFinal()) { | |
| 727 | + return toClass.implementedBy(this, | |
| 728 | + fromClass.getClassDeclaration()); | |
| 729 | + } | |
| 730 | + | |
| 731 | + // The code here used to omit this case. If both types | |
| 732 | + // involved in a cast are interfaces, then JLS 5.5 requires | |
| 733 | + // that we do a simple test -- make sure none of the methods | |
| 734 | + // in toClass and fromClass have the same signature but | |
| 735 | + // different return types. (bug number 4028359) | |
| 736 | + if (toClass.isInterface() && fromClass.isInterface()) { | |
| 737 | + return toClass.couldImplement(fromClass); | |
| 738 | + } | |
| 739 | + | |
| 740 | + return toClass.isInterface() || | |
| 741 | + fromClass.isInterface() || | |
| 742 | + fromClass.superClassOf(this, toClass.getClassDeclaration()); | |
| 743 | + } | |
| 744 | + if (to.isType(TC_ARRAY)) { | |
| 745 | + if (from.isType(TC_ARRAY)) { | |
| 746 | + Type t1 = from.getElementType(); | |
| 747 | + Type t2 = to.getElementType(); | |
| 748 | + while ((t1.getTypeCode() == TC_ARRAY) | |
| 749 | + && (t2.getTypeCode() == TC_ARRAY)) { | |
| 750 | + t1 = t1.getElementType(); | |
| 751 | + t2 = t2.getElementType(); | |
| 752 | + } | |
| 753 | + if (t1.inMask(TM_ARRAY|TM_CLASS) && | |
| 754 | + t2.inMask(TM_ARRAY|TM_CLASS)) { | |
| 755 | + return explicitCast(t1, t2); | |
| 756 | + } | |
| 757 | + } else if (from == Type.tObject || from == Type.tCloneable | |
| 758 | + || from == Type.tSerializable) | |
| 759 | + return true; | |
| 760 | + } | |
| 761 | + return false; | |
| 762 | + } | |
| 763 | + | |
| 764 | + /** | |
| 765 | + * Flags. | |
| 766 | + */ | |
| 767 | + public int getFlags() { | |
| 768 | + return env.getFlags(); | |
| 769 | + } | |
| 770 | + | |
| 771 | + /** | |
| 772 | + * Debugging flags. There used to be a method debug() | |
| 773 | + * that has been replaced because -g has changed meaning | |
| 774 | + * (it now cooperates with -O and line number, variable | |
| 775 | + * range and source file info can be toggled separately). | |
| 776 | + */ | |
| 777 | + public final boolean debug_lines() { | |
| 778 | + return (getFlags() & F_DEBUG_LINES) != 0; | |
| 779 | + } | |
| 780 | + public final boolean debug_vars() { | |
| 781 | + return (getFlags() & F_DEBUG_VARS) != 0; | |
| 782 | + } | |
| 783 | + public final boolean debug_source() { | |
| 784 | + return (getFlags() & F_DEBUG_SOURCE) != 0; | |
| 785 | + } | |
| 786 | + | |
| 787 | + /** | |
| 788 | + * Optimization flags. There used to be a method optimize() | |
| 789 | + * that has been replaced because -O has changed meaning in | |
| 790 | + * javac to be replaced with -O and -O:interclass. | |
| 791 | + */ | |
| 792 | + public final boolean opt() { | |
| 793 | + return (getFlags() & F_OPT) != 0; | |
| 794 | + } | |
| 795 | + public final boolean opt_interclass() { | |
| 796 | + return (getFlags() & F_OPT_INTERCLASS) != 0; | |
| 797 | + } | |
| 798 | + | |
| 799 | + /** | |
| 800 | + * Verbose | |
| 801 | + */ | |
| 802 | + public final boolean verbose() { | |
| 803 | + return (getFlags() & F_VERBOSE) != 0; | |
| 804 | + } | |
| 805 | + | |
| 806 | + /** | |
| 807 | + * Dump debugging stuff | |
| 808 | + */ | |
| 809 | + public final boolean dump() { | |
| 810 | + return (getFlags() & F_DUMP) != 0; | |
| 811 | + } | |
| 812 | + | |
| 813 | + /** | |
| 814 | + * Verbose | |
| 815 | + */ | |
| 816 | + public final boolean warnings() { | |
| 817 | + return (getFlags() & F_WARNINGS) != 0; | |
| 818 | + } | |
| 819 | + | |
| 820 | + /** | |
| 821 | + * Dependencies | |
| 822 | + */ | |
| 823 | + public final boolean dependencies() { | |
| 824 | + return (getFlags() & F_DEPENDENCIES) != 0; | |
| 825 | + } | |
| 826 | + | |
| 827 | + /** | |
| 828 | + * Print Dependencies to stdout | |
| 829 | + */ | |
| 830 | + public final boolean print_dependencies() { | |
| 831 | + return (getFlags() & F_PRINT_DEPENDENCIES) != 0; | |
| 832 | + } | |
| 833 | + | |
| 834 | + /** | |
| 835 | + * Deprecation warnings are enabled. | |
| 836 | + */ | |
| 837 | + public final boolean deprecation() { | |
| 838 | + return (getFlags() & F_DEPRECATION) != 0; | |
| 839 | + } | |
| 840 | + | |
| 841 | + /** | |
| 842 | + * Do not support virtual machines before version 1.2. | |
| 843 | + * This option is not supported and is only here for testing purposes. | |
| 844 | + */ | |
| 845 | + public final boolean version12() { | |
| 846 | + return (getFlags() & F_VERSION12) != 0; | |
| 847 | + } | |
| 848 | + | |
| 849 | + /** | |
| 850 | + * Floating point is strict by default | |
| 851 | + */ | |
| 852 | + public final boolean strictdefault() { | |
| 853 | + return (getFlags() & F_STRICTDEFAULT) != 0; | |
| 854 | + } | |
| 855 | + | |
| 856 | + /** | |
| 857 | + * Release resources, if any. | |
| 858 | + */ | |
| 859 | + public void shutdown() { | |
| 860 | + if (env != null) { | |
| 861 | + env.shutdown(); | |
| 862 | + } | |
| 863 | + } | |
| 864 | + | |
| 865 | + /** | |
| 866 | + * Issue an error. | |
| 867 | + * source - the input source, usually a file name string | |
| 868 | + * offset - the offset in the source of the error | |
| 869 | + * err - the error number (as defined in this interface) | |
| 870 | + * arg1 - an optional argument to the error (null if not applicable) | |
| 871 | + * arg2 - a second optional argument to the error (null if not applicable) | |
| 872 | + * arg3 - a third optional argument to the error (null if not applicable) | |
| 873 | + */ | |
| 874 | + public void error(Object source, long where, String err, Object arg1, Object arg2, Object arg3) { | |
| 875 | + env.error(source, where, err, arg1, arg2, arg3); | |
| 876 | + } | |
| 877 | + public final void error(long where, String err, Object arg1, Object arg2, Object arg3) { | |
| 878 | + error(source, where, err, arg1, arg2, arg3); | |
| 879 | + } | |
| 880 | + public final void error(long where, String err, Object arg1, Object arg2) { | |
| 881 | + error(source, where, err, arg1, arg2, null); | |
| 882 | + } | |
| 883 | + public final void error(long where, String err, Object arg1) { | |
| 884 | + error(source, where, err, arg1, null, null); | |
| 885 | + } | |
| 886 | + public final void error(long where, String err) { | |
| 887 | + error(source, where, err, null, null, null); | |
| 888 | + } | |
| 889 | + | |
| 890 | + /** | |
| 891 | + * Output a string. This can either be an error message or something | |
| 892 | + * for debugging. This should be used instead of println. | |
| 893 | + */ | |
| 894 | + public void output(String msg) { | |
| 895 | + env.output(msg); | |
| 896 | + } | |
| 897 | + | |
| 898 | + private static boolean debugging = (System.getProperty("javac.debug") != null); | |
| 899 | + | |
| 900 | + public static void debugOutput(Object msg) { | |
| 901 | + if (Environment.debugging) | |
| 902 | + System.out.println(msg.toString()); | |
| 903 | + } | |
| 904 | + | |
| 905 | + /** | |
| 906 | + * set character encoding name | |
| 907 | + */ | |
| 908 | + public void setCharacterEncoding(String encoding) { | |
| 909 | + this.encoding = encoding; | |
| 910 | + } | |
| 911 | + | |
| 912 | + /** | |
| 913 | + * Return character encoding name | |
| 914 | + */ | |
| 915 | + public String getCharacterEncoding() { | |
| 916 | + return encoding; | |
| 917 | + } | |
| 918 | + | |
| 919 | + /** | |
| 920 | + * Return major version to use in generated class files. | |
| 921 | + */ | |
| 922 | + public short getMajorVersion() { | |
| 923 | + if (env==null) return JAVA_DEFAULT_VERSION; // needed for javah | |
| 924 | + return env.getMajorVersion(); | |
| 925 | + } | |
| 926 | + | |
| 927 | + /** | |
| 928 | + * Return minor version to use in generated class files. | |
| 929 | + */ | |
| 930 | + public short getMinorVersion() { | |
| 931 | + if (env==null) return JAVA_DEFAULT_MINOR_VERSION; // needed for javah | |
| 932 | + return env.getMinorVersion(); | |
| 933 | + } | |
| 934 | + | |
| 935 | +// JCOV | |
| 936 | + /** | |
| 937 | + * get coverage flag | |
| 938 | + */ | |
| 939 | + public final boolean coverage() { | |
| 940 | + return (getFlags() & F_COVERAGE) != 0; | |
| 941 | + } | |
| 942 | + | |
| 943 | + /** | |
| 944 | + * get flag of generation the coverage data file | |
| 945 | + */ | |
| 946 | + public final boolean covdata() { | |
| 947 | + return (getFlags() & F_COVDATA) != 0; | |
| 948 | + } | |
| 949 | + | |
| 950 | + /** | |
| 951 | + * Return the coverage data file | |
| 952 | + */ | |
| 953 | + public File getcovFile() { | |
| 954 | + return env.getcovFile(); | |
| 955 | + } | |
| 956 | + | |
| 957 | +// end JCOV | |
| 958 | + | |
| 959 | + /** | |
| 960 | + * Debug tracing. | |
| 961 | + * Currently, this code is used only for tracing the loading and | |
| 962 | + * checking of classes, particularly the demand-driven aspects. | |
| 963 | + * This code should probably be integrated with 'debugOutput' above, | |
| 964 | + * but we need to give more thought to the issue of classifying debugging | |
| 965 | + * messages and allowing those only those of interest to be enabled. | |
| 966 | + * | |
| 967 | + * Calls to these methods are generally conditioned on the final variable | |
| 968 | + * 'Constants.tracing', which allows the calls to be completely omitted | |
| 969 | + * in a production release to avoid space and time overhead. | |
| 970 | + */ | |
| 971 | + | |
| 972 | + private static boolean dependtrace = | |
| 973 | + (System.getProperty("javac.trace.depend") != null); | |
| 974 | + | |
| 975 | + public void dtEnter(String s) { | |
| 976 | + if (dependtrace) System.out.println(">>> " + s); | |
| 977 | + } | |
| 978 | + | |
| 979 | + public void dtExit(String s) { | |
| 980 | + if (dependtrace) System.out.println("<<< " + s); | |
| 981 | + } | |
| 982 | + | |
| 983 | + public void dtEvent(String s) { | |
| 984 | + if (dependtrace) System.out.println(s); | |
| 985 | + } | |
| 986 | + | |
| 987 | + /** | |
| 988 | + * Enable diagnostic dump of class modifier bits, including those | |
| 989 | + * in InnerClasses attributes, as they are written to the classfile. | |
| 990 | + * In the future, may also enable dumping field and method modifiers. | |
| 991 | + */ | |
| 992 | + | |
| 993 | + private static boolean dumpmodifiers = | |
| 994 | + (System.getProperty("javac.dump.modifiers") != null); | |
| 995 | + | |
| 996 | + public boolean dumpModifiers() { return dumpmodifiers; } | |
| 997 | + | |
| 998 | +} | |
| @@ -0,0 +1,329 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +import java.util.Hashtable; | |
| 29 | +import java.io.PrintStream; | |
| 30 | +import java.util.Enumeration; | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * A class to represent identifiers.<p> | |
| 34 | + * | |
| 35 | + * An identifier instance is very similar to a String. The difference | |
| 36 | + * is that identifier can't be instanciated directly, instead they are | |
| 37 | + * looked up in a hash table. This means that identifiers with the same | |
| 38 | + * name map to the same identifier object. This makes comparisons of | |
| 39 | + * identifiers much faster.<p> | |
| 40 | + * | |
| 41 | + * A lot of identifiers are qualified, that is they have '.'s in them. | |
| 42 | + * Each qualified identifier is chopped up into the qualifier and the | |
| 43 | + * name. The qualifier is cached in the value field.<p> | |
| 44 | + * | |
| 45 | + * Unqualified identifiers can have a type. This type is an integer that | |
| 46 | + * can be used by a scanner as a token value. This value has to be set | |
| 47 | + * using the setType method.<p> | |
| 48 | + * | |
| 49 | + * WARNING: The contents of this source file are not part of any | |
| 50 | + * supported API. Code that depends on them does so at its own risk: | |
| 51 | + * they are subject to change or removal without notice. | |
| 52 | + * | |
| 53 | + * @author Arthur van Hoff | |
| 54 | + */ | |
| 55 | + | |
| 56 | +public final | |
| 57 | +class Identifier implements Constants { | |
| 58 | + /** | |
| 59 | + * The hashtable of identifiers | |
| 60 | + */ | |
| 61 | + static Hashtable hash = new Hashtable(3001, 0.5f); | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * The name of the identifier | |
| 65 | + */ | |
| 66 | + String name; | |
| 67 | + | |
| 68 | + /** | |
| 69 | + * The value of the identifier, for keywords this is an | |
| 70 | + * instance of class Integer, for qualified names this is | |
| 71 | + * another identifier (the qualifier). | |
| 72 | + */ | |
| 73 | + Object value; | |
| 74 | + | |
| 75 | + /** | |
| 76 | + * The Type which corresponds to this Identifier. This is used as | |
| 77 | + * cache for Type.tClass() and shouldn't be used outside of that | |
| 78 | + * context. | |
| 79 | + */ | |
| 80 | + Type typeObject = null; | |
| 81 | + | |
| 82 | + /** | |
| 83 | + * The index of INNERCLASS_PREFIX in the name, or -1 if none. | |
| 84 | + */ | |
| 85 | + private int ipos; | |
| 86 | + | |
| 87 | + /** | |
| 88 | + * Construct an identifier. Don't call this directly, | |
| 89 | + * use lookup instead. | |
| 90 | + * @see Identifier.lookup | |
| 91 | + */ | |
| 92 | + private Identifier(String name) { | |
| 93 | + this.name = name; | |
| 94 | + this.ipos = name.indexOf(INNERCLASS_PREFIX); | |
| 95 | + } | |
| 96 | + | |
| 97 | + /** | |
| 98 | + * Get the type of the identifier. | |
| 99 | + */ | |
| 100 | + int getType() { | |
| 101 | + return ((value != null) && (value instanceof Integer)) ? | |
| 102 | + ((Integer)value).intValue() : IDENT; | |
| 103 | + } | |
| 104 | + | |
| 105 | + /** | |
| 106 | + * Set the type of the identifier. | |
| 107 | + */ | |
| 108 | + void setType(int t) { | |
| 109 | + value = new Integer(t); | |
| 110 | + //System.out.println("type(" + this + ")=" + t); | |
| 111 | + } | |
| 112 | + | |
| 113 | + /** | |
| 114 | + * Lookup an identifier. | |
| 115 | + */ | |
| 116 | + public static synchronized Identifier lookup(String s) { | |
| 117 | + //System.out.println("lookup(" + s + ")"); | |
| 118 | + Identifier id = (Identifier)hash.get(s); | |
| 119 | + if (id == null) { | |
| 120 | + hash.put(s, id = new Identifier(s)); | |
| 121 | + } | |
| 122 | + return id; | |
| 123 | + } | |
| 124 | + | |
| 125 | + /** | |
| 126 | + * Lookup a qualified identifier. | |
| 127 | + */ | |
| 128 | + public static Identifier lookup(Identifier q, Identifier n) { | |
| 129 | + // lookup("", x) => x | |
| 130 | + if (q == idNull) return n; | |
| 131 | + // lookup(lookupInner(c, ""), n) => lookupInner(c, lookup("", n)) | |
| 132 | + if (q.name.charAt(q.name.length()-1) == INNERCLASS_PREFIX) | |
| 133 | + return lookup(q.name+n.name); | |
| 134 | + Identifier id = lookup(q + "." + n); | |
| 135 | + if (!n.isQualified() && !q.isInner()) | |
| 136 | + id.value = q; | |
| 137 | + return id; | |
| 138 | + } | |
| 139 | + | |
| 140 | + /** | |
| 141 | + * Lookup an inner identifier. | |
| 142 | + * (Note: n can be idNull.) | |
| 143 | + */ | |
| 144 | + public static Identifier lookupInner(Identifier c, Identifier n) { | |
| 145 | + Identifier id; | |
| 146 | + if (c.isInner()) { | |
| 147 | + if (c.name.charAt(c.name.length()-1) == INNERCLASS_PREFIX) | |
| 148 | + id = lookup(c.name+n); | |
| 149 | + else | |
| 150 | + id = lookup(c, n); | |
| 151 | + } else { | |
| 152 | + id = lookup(c + "." + INNERCLASS_PREFIX + n); | |
| 153 | + } | |
| 154 | + id.value = c.value; | |
| 155 | + return id; | |
| 156 | + } | |
| 157 | + | |
| 158 | + /** | |
| 159 | + * Convert to a string. | |
| 160 | + */ | |
| 161 | + public String toString() { | |
| 162 | + return name; | |
| 163 | + } | |
| 164 | + | |
| 165 | + /** | |
| 166 | + * Check if the name is qualified (ie: it contains a '.'). | |
| 167 | + */ | |
| 168 | + public boolean isQualified() { | |
| 169 | + if (value == null) { | |
| 170 | + int idot = ipos; | |
| 171 | + if (idot <= 0) | |
| 172 | + idot = name.length(); | |
| 173 | + else | |
| 174 | + idot -= 1; // back up over previous dot | |
| 175 | + int index = name.lastIndexOf('.', idot-1); | |
| 176 | + value = (index < 0) ? idNull : Identifier.lookup(name.substring(0, index)); | |
| 177 | + } | |
| 178 | + return (value instanceof Identifier) && (value != idNull); | |
| 179 | + } | |
| 180 | + | |
| 181 | + /** | |
| 182 | + * Return the qualifier. The null identifier is returned if | |
| 183 | + * the name was not qualified. The qualifier does not include | |
| 184 | + * any inner part of the name. | |
| 185 | + */ | |
| 186 | + public Identifier getQualifier() { | |
| 187 | + return isQualified() ? (Identifier)value : idNull; | |
| 188 | + } | |
| 189 | + | |
| 190 | + /** | |
| 191 | + * Return the unqualified name. | |
| 192 | + * In the case of an inner name, the unqualified name | |
| 193 | + * will itself contain components. | |
| 194 | + */ | |
| 195 | + public Identifier getName() { | |
| 196 | + return isQualified() ? | |
| 197 | + Identifier.lookup(name.substring(((Identifier)value).name.length() + 1)) : this; | |
| 198 | + } | |
| 199 | + | |
| 200 | + /** A space character, which precedes the first inner class | |
| 201 | + * name in a qualified name, and thus marks the qualification | |
| 202 | + * as involving inner classes, instead of merely packages.<p> | |
| 203 | + * Ex: <tt>java.util.Vector. Enumerator</tt>. | |
| 204 | + */ | |
| 205 | + public static final char INNERCLASS_PREFIX = ' '; | |
| 206 | + | |
| 207 | + /* Explanation: | |
| 208 | + * Since much of the compiler's low-level name resolution code | |
| 209 | + * operates in terms of Identifier objects. This includes the | |
| 210 | + * code which walks around the file system and reports what | |
| 211 | + * classes are where. It is important to get nesting information | |
| 212 | + * right as early as possible, since it affects the spelling of | |
| 213 | + * signatures. Thus, the low-level import and resolve code must | |
| 214 | + * be able Identifier type must be able to report the nesting | |
| 215 | + * of types, which implied that that information must be carried | |
| 216 | + * by Identifiers--or that the low-level interfaces be significantly | |
| 217 | + * changed. | |
| 218 | + */ | |
| 219 | + | |
| 220 | + /** | |
| 221 | + * Check if the name is inner (ie: it contains a ' '). | |
| 222 | + */ | |
| 223 | + public boolean isInner() { | |
| 224 | + return (ipos > 0); | |
| 225 | + } | |
| 226 | + | |
| 227 | + /** | |
| 228 | + * Return the class name, without its qualifier, | |
| 229 | + * and with any nesting flattened into a new qualfication structure. | |
| 230 | + * If the original identifier is inner, | |
| 231 | + * the result will be qualified, and can be further | |
| 232 | + * decomposed by means of <tt>getQualifier</tt> and <tt>getName</tt>. | |
| 233 | + * <p> | |
| 234 | + * For example: | |
| 235 | + * <pre> | |
| 236 | + * Identifier id = Identifier.lookup("pkg.Foo. Bar"); | |
| 237 | + * id.getName().name => "Foo. Bar" | |
| 238 | + * id.getFlatName().name => "Foo.Bar" | |
| 239 | + * </pre> | |
| 240 | + */ | |
| 241 | + public Identifier getFlatName() { | |
| 242 | + if (isQualified()) { | |
| 243 | + return getName().getFlatName(); | |
| 244 | + } | |
| 245 | + if (ipos > 0 && name.charAt(ipos-1) == '.') { | |
| 246 | + if (ipos+1 == name.length()) { | |
| 247 | + // last component is idNull | |
| 248 | + return Identifier.lookup(name.substring(0,ipos-1)); | |
| 249 | + } | |
| 250 | + String n = name.substring(ipos+1); | |
| 251 | + String t = name.substring(0,ipos); | |
| 252 | + return Identifier.lookup(t+n); | |
| 253 | + } | |
| 254 | + // Not inner. Just return the same as getName() | |
| 255 | + return this; | |
| 256 | + } | |
| 257 | + | |
| 258 | + public Identifier getTopName() { | |
| 259 | + if (!isInner()) return this; | |
| 260 | + return Identifier.lookup(getQualifier(), getFlatName().getHead()); | |
| 261 | + } | |
| 262 | + | |
| 263 | + /** | |
| 264 | + * Yet another way to slice qualified identifiers: | |
| 265 | + * The head of an identifier is its first qualifier component, | |
| 266 | + * and the tail is the rest of them. | |
| 267 | + */ | |
| 268 | + public Identifier getHead() { | |
| 269 | + Identifier id = this; | |
| 270 | + while (id.isQualified()) | |
| 271 | + id = id.getQualifier(); | |
| 272 | + return id; | |
| 273 | + } | |
| 274 | + | |
| 275 | + /** | |
| 276 | + * @see getHead | |
| 277 | + */ | |
| 278 | + public Identifier getTail() { | |
| 279 | + Identifier id = getHead(); | |
| 280 | + if (id == this) | |
| 281 | + return idNull; | |
| 282 | + else | |
| 283 | + return Identifier.lookup(name.substring(id.name.length() + 1)); | |
| 284 | + } | |
| 285 | + | |
| 286 | + // Unfortunately, the current structure of the compiler requires | |
| 287 | + // that the resolveName() family of methods (which appear in | |
| 288 | + // Environment.java, Context.java, and ClassDefinition.java) raise | |
| 289 | + // no exceptions and emit no errors. When we are in resolveName() | |
| 290 | + // and we find a method that is ambiguous, we need to | |
| 291 | + // unambiguously mark it as such, so that later stages of the | |
| 292 | + // compiler realize that they should give an ambig.class rather than | |
| 293 | + // a class.not.found error. To mark it we add a special prefix | |
| 294 | + // which cannot occur in the program source. The routines below | |
| 295 | + // are used to check, add, and remove this prefix. | |
| 296 | + // (part of solution for 4059855). | |
| 297 | + | |
| 298 | + /** | |
| 299 | + * A special prefix to add to ambiguous names. | |
| 300 | + */ | |
| 301 | + private static final String ambigPrefix = "<<ambiguous>>"; | |
| 302 | + | |
| 303 | + /** | |
| 304 | + * Determine whether an Identifier has been marked as ambiguous. | |
| 305 | + */ | |
| 306 | + public boolean hasAmbigPrefix() { | |
| 307 | + return (name.startsWith(ambigPrefix)); | |
| 308 | + } | |
| 309 | + | |
| 310 | + /** | |
| 311 | + * Add ambigPrefix to `this' to make a new Identifier marked as | |
| 312 | + * ambiguous. It is important that this new Identifier not refer | |
| 313 | + * to an existing class. | |
| 314 | + */ | |
| 315 | + public Identifier addAmbigPrefix() { | |
| 316 | + return Identifier.lookup(ambigPrefix + name); | |
| 317 | + } | |
| 318 | + | |
| 319 | + /** | |
| 320 | + * Remove the ambigPrefix from `this' to get the original identifier. | |
| 321 | + */ | |
| 322 | + public Identifier removeAmbigPrefix() { | |
| 323 | + if (hasAmbigPrefix()) { | |
| 324 | + return Identifier.lookup(name.substring(ambigPrefix.length())); | |
| 325 | + } else { | |
| 326 | + return this; | |
| 327 | + } | |
| 328 | + } | |
| 329 | +} | |
| @@ -0,0 +1,91 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Information about the occurrence of an identifier. | |
| 30 | + * The parser produces these to represent name which cannot yet be | |
| 31 | + * bound to field definitions. | |
| 32 | + * | |
| 33 | + * WARNING: The contents of this source file are not part of any | |
| 34 | + * supported API. Code that depends on them does so at its own risk: | |
| 35 | + * they are subject to change or removal without notice. | |
| 36 | + * | |
| 37 | + * @see | |
| 38 | + */ | |
| 39 | + | |
| 40 | +public | |
| 41 | +class IdentifierToken { | |
| 42 | + long where; | |
| 43 | + int modifiers; | |
| 44 | + Identifier id; | |
| 45 | + | |
| 46 | + public IdentifierToken(long where, Identifier id) { | |
| 47 | + this.where = where; | |
| 48 | + this.id = id; | |
| 49 | + } | |
| 50 | + | |
| 51 | + /** Use this constructor when the identifier is synthesized. | |
| 52 | + * The location will be 0. | |
| 53 | + */ | |
| 54 | + public IdentifierToken(Identifier id) { | |
| 55 | + this.where = 0; | |
| 56 | + this.id = id; | |
| 57 | + } | |
| 58 | + | |
| 59 | + public IdentifierToken(long where, Identifier id, int modifiers) { | |
| 60 | + this.where = where; | |
| 61 | + this.id = id; | |
| 62 | + this.modifiers = modifiers; | |
| 63 | + } | |
| 64 | + | |
| 65 | + /** The source location of this identifier occurrence. */ | |
| 66 | + public long getWhere() { | |
| 67 | + return where; | |
| 68 | + } | |
| 69 | + | |
| 70 | + /** The identifier itself (possibly qualified). */ | |
| 71 | + public Identifier getName() { | |
| 72 | + return id; | |
| 73 | + } | |
| 74 | + | |
| 75 | + /** The modifiers associated with the occurrence, if any. */ | |
| 76 | + public int getModifiers() { | |
| 77 | + return modifiers; | |
| 78 | + } | |
| 79 | + | |
| 80 | + public String toString() { | |
| 81 | + return id.toString(); | |
| 82 | + } | |
| 83 | + | |
| 84 | + /** | |
| 85 | + * Return defaultWhere if id is null or id.where is missing (0). | |
| 86 | + * Otherwise, return id.where. | |
| 87 | + */ | |
| 88 | + public static long getWhere(IdentifierToken id, long defaultWhere) { | |
| 89 | + return (id != null && id.where != 0) ? id.where : defaultWhere; | |
| 90 | + } | |
| 91 | +} | |
| @@ -0,0 +1,503 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +import java.util.Hashtable; | |
| 29 | +import java.util.Vector; | |
| 30 | +import java.util.Enumeration; | |
| 31 | +import java.util.List; | |
| 32 | +import java.util.Collections; | |
| 33 | +import java.io.IOException; | |
| 34 | + | |
| 35 | +/** | |
| 36 | + * This class describes the classes and packages imported | |
| 37 | + * from a source file. A Hashtable called bindings is maintained | |
| 38 | + * to quickly map symbol names to classes. This table is flushed | |
| 39 | + * everytime a new import is added. | |
| 40 | + * | |
| 41 | + * A class name is resolved as follows: | |
| 42 | + * - if it is a qualified name then return the corresponding class | |
| 43 | + * - if the name corresponds to an individually imported class then return that class | |
| 44 | + * - check if the class is defined in any of the imported packages, | |
| 45 | + * if it is then return it, make sure it is defined in only one package | |
| 46 | + * - assume that the class is defined in the current package | |
| 47 | + * | |
| 48 | + * WARNING: The contents of this source file are not part of any | |
| 49 | + * supported API. Code that depends on them does so at its own risk: | |
| 50 | + * they are subject to change or removal without notice. | |
| 51 | + */ | |
| 52 | + | |
| 53 | +public | |
| 54 | +class Imports implements Constants { | |
| 55 | + /** | |
| 56 | + * The current package, which is implicitly imported, | |
| 57 | + * and has precedence over other imported packages. | |
| 58 | + */ | |
| 59 | + Identifier currentPackage = idNull; | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * A location for the current package declaration. Used to | |
| 63 | + * report errors against the current package. | |
| 64 | + */ | |
| 65 | + long currentPackageWhere = 0; | |
| 66 | + | |
| 67 | + /** | |
| 68 | + * The imported classes, including memoized imports from packages. | |
| 69 | + */ | |
| 70 | + Hashtable classes = new Hashtable(); | |
| 71 | + | |
| 72 | + /** | |
| 73 | + * The imported package identifiers. This will not contain duplicate | |
| 74 | + * imports for the same package. It will also not contain the | |
| 75 | + * current package. | |
| 76 | + */ | |
| 77 | + Vector packages = new Vector(); | |
| 78 | + | |
| 79 | + /** | |
| 80 | + * The (originally) imported classes. | |
| 81 | + * A vector of IdentifierToken. | |
| 82 | + */ | |
| 83 | + Vector singles = new Vector(); | |
| 84 | + | |
| 85 | + /** | |
| 86 | + * Are the import names checked yet? | |
| 87 | + */ | |
| 88 | + protected int checked; | |
| 89 | + | |
| 90 | + /** | |
| 91 | + * Constructor, always import java.lang. | |
| 92 | + */ | |
| 93 | + public Imports(Environment env) { | |
| 94 | + addPackage(idJavaLang); | |
| 95 | + } | |
| 96 | + | |
| 97 | + /** | |
| 98 | + * Check the names of the imports. | |
| 99 | + */ | |
| 100 | + public synchronized void resolve(Environment env) { | |
| 101 | + if (checked != 0) { | |
| 102 | + return; | |
| 103 | + } | |
| 104 | + checked = -1; | |
| 105 | + | |
| 106 | + // After all class information has been read, now we can | |
| 107 | + // safely inspect import information for errors. | |
| 108 | + // If we did this before all parsing was finished, | |
| 109 | + // we could get vicious circularities, since files can | |
| 110 | + // import each others' classes. | |
| 111 | + | |
| 112 | + // A note: the resolution of the package java.lang takes place | |
| 113 | + // in the sun.tools.javac.BatchEnvironment#setExemptPackages(). | |
| 114 | + | |
| 115 | + // Make sure that the current package's name does not collide | |
| 116 | + // with the name of an existing class. (bug 4101529) | |
| 117 | + // | |
| 118 | + // This change has been backed out because, on WIN32, it | |
| 119 | + // failed to distinguish between java.awt.event and | |
| 120 | + // java.awt.Event when looking for a directory. We will | |
| 121 | + // add this back in later. | |
| 122 | + // | |
| 123 | + // if (currentPackage != idNull) { | |
| 124 | + // Identifier resolvedName = | |
| 125 | + // env.resolvePackageQualifiedName(currentPackage); | |
| 126 | + // | |
| 127 | + // Identifier className = resolvedName.getTopName(); | |
| 128 | + // | |
| 129 | + // if (importable(className, env)) { | |
| 130 | + // // The name of the current package is also the name | |
| 131 | + // // of a class. | |
| 132 | + // env.error(currentPackageWhere, "package.class.conflict", | |
| 133 | + // currentPackage, className); | |
| 134 | + // } | |
| 135 | + // } | |
| 136 | + | |
| 137 | + Vector resolvedPackages = new Vector(); | |
| 138 | + for (Enumeration e = packages.elements() ; e.hasMoreElements() ;) { | |
| 139 | + IdentifierToken t = (IdentifierToken)e.nextElement(); | |
| 140 | + Identifier nm = t.getName(); | |
| 141 | + long where = t.getWhere(); | |
| 142 | + | |
| 143 | + // Check to see if this package is exempt from the "exists" | |
| 144 | + // check. See the note in | |
| 145 | + // sun.tools.javac.BatchEnvironment#setExemptPackages() | |
| 146 | + // for more information. | |
| 147 | + if (env.isExemptPackage(nm)) { | |
| 148 | + resolvedPackages.addElement(t); | |
| 149 | + continue; | |
| 150 | + } | |
| 151 | + | |
| 152 | + // (Note: This code is moved from BatchParser.importPackage().) | |
| 153 | + try { | |
| 154 | + Identifier rnm = env.resolvePackageQualifiedName(nm); | |
| 155 | + if (importable(rnm, env)) { | |
| 156 | + // This name is a real class; better not be a package too. | |
| 157 | + if (env.getPackage(rnm.getTopName()).exists()) { | |
| 158 | + env.error(where, "class.and.package", | |
| 159 | + rnm.getTopName()); | |
| 160 | + } | |
| 161 | + // Pass an "inner" name to the imports. | |
| 162 | + if (!rnm.isInner()) | |
| 163 | + rnm = Identifier.lookupInner(rnm, idNull); | |
| 164 | + nm = rnm; | |
| 165 | + } else if (!env.getPackage(nm).exists()) { | |
| 166 | + env.error(where, "package.not.found", nm, "import"); | |
| 167 | + } else if (rnm.isInner()) { | |
| 168 | + // nm exists, and rnm.getTopName() is a parent package | |
| 169 | + env.error(where, "class.and.package", rnm.getTopName()); | |
| 170 | + } | |
| 171 | + resolvedPackages.addElement(new IdentifierToken(where, nm)); | |
| 172 | + } catch (IOException ee) { | |
| 173 | + env.error(where, "io.exception", "import"); | |
| 174 | + } | |
| 175 | + } | |
| 176 | + packages = resolvedPackages; | |
| 177 | + | |
| 178 | + for (Enumeration e = singles.elements() ; e.hasMoreElements() ;) { | |
| 179 | + IdentifierToken t = (IdentifierToken)e.nextElement(); | |
| 180 | + Identifier nm = t.getName(); | |
| 181 | + long where = t.getWhere(); | |
| 182 | + Identifier pkg = nm.getQualifier(); | |
| 183 | + | |
| 184 | + // (Note: This code is moved from BatchParser.importClass().) | |
| 185 | + nm = env.resolvePackageQualifiedName(nm); | |
| 186 | + if (!env.classExists(nm.getTopName())) { | |
| 187 | + env.error(where, "class.not.found", nm, "import"); | |
| 188 | + } | |
| 189 | + | |
| 190 | + // (Note: This code is moved from Imports.addClass().) | |
| 191 | + Identifier snm = nm.getFlatName().getName(); | |
| 192 | + | |
| 193 | + // make sure it isn't already imported explicitly | |
| 194 | + Identifier className = (Identifier)classes.get(snm); | |
| 195 | + if (className != null) { | |
| 196 | + Identifier f1 = Identifier.lookup(className.getQualifier(), | |
| 197 | + className.getFlatName()); | |
| 198 | + Identifier f2 = Identifier.lookup(nm.getQualifier(), | |
| 199 | + nm.getFlatName()); | |
| 200 | + if (!f1.equals(f2)) { | |
| 201 | + env.error(where, "ambig.class", nm, className); | |
| 202 | + } | |
| 203 | + } | |
| 204 | + classes.put(snm, nm); | |
| 205 | + | |
| 206 | + | |
| 207 | + // The code here needs to check to see, if we | |
| 208 | + // are importing an inner class, that all of its | |
| 209 | + // enclosing classes are visible to us. To check this, | |
| 210 | + // we need to construct a definition for the class. | |
| 211 | + // The code here used to call... | |
| 212 | + // | |
| 213 | + // ClassDefinition def = env.getClassDefinition(nm); | |
| 214 | + // | |
| 215 | + // ...but that interfered with the basicCheck()'ing of | |
| 216 | + // interfaces in certain cases (bug no. 4086139). Never | |
| 217 | + // fear. Instead we load the class with a call to the | |
| 218 | + // new getClassDefinitionNoCheck() which does no basicCheck() and | |
| 219 | + // lets us answer the questions we are interested in w/o | |
| 220 | + // interfering with the demand-driven nature of basicCheck(). | |
| 221 | + | |
| 222 | + try { | |
| 223 | + // Get a declaration | |
| 224 | + ClassDeclaration decl = env.getClassDeclaration(nm); | |
| 225 | + | |
| 226 | + // Get the definition (no env argument) | |
| 227 | + ClassDefinition def = decl.getClassDefinitionNoCheck(env); | |
| 228 | + | |
| 229 | + // Get the true name of the package containing this class. | |
| 230 | + // `pkg' from above is insufficient. It includes the | |
| 231 | + // names of our enclosing classes. Fix for 4086815. | |
| 232 | + Identifier importedPackage = def.getName().getQualifier(); | |
| 233 | + | |
| 234 | + // Walk out the outerClass chain, ensuring that each level | |
| 235 | + // is visible from our perspective. | |
| 236 | + for (; def != null; def = def.getOuterClass()) { | |
| 237 | + if (def.isPrivate() | |
| 238 | + || !(def.isPublic() | |
| 239 | + || importedPackage.equals(currentPackage))) { | |
| 240 | + env.error(where, "cant.access.class", def); | |
| 241 | + break; | |
| 242 | + } | |
| 243 | + } | |
| 244 | + } catch (AmbiguousClass ee) { | |
| 245 | + env.error(where, "ambig.class", ee.name1, ee.name2); | |
| 246 | + } catch (ClassNotFound ee) { | |
| 247 | + env.error(where, "class.not.found", ee.name, "import"); | |
| 248 | + } | |
| 249 | + } | |
| 250 | + checked = 1; | |
| 251 | + } | |
| 252 | + | |
| 253 | + /** | |
| 254 | + * Lookup a class, given the current set of imports, | |
| 255 | + * AmbiguousClass exception is thrown if the name can be | |
| 256 | + * resolved in more than one way. A ClassNotFound exception | |
| 257 | + * is thrown if the class is not found in the imported classes | |
| 258 | + * and packages. | |
| 259 | + */ | |
| 260 | + public synchronized Identifier resolve(Environment env, Identifier nm) throws ClassNotFound { | |
| 261 | + if (tracing) env.dtEnter("Imports.resolve: " + nm); | |
| 262 | + | |
| 263 | + // If the class has the special ambiguous prefix, then we will | |
| 264 | + // get the original AmbiguousClass exception by removing the | |
| 265 | + // prefix and proceeding in the normal fashion. | |
| 266 | + // (part of solution for 4059855) | |
| 267 | + if (nm.hasAmbigPrefix()) { | |
| 268 | + nm = nm.removeAmbigPrefix(); | |
| 269 | + } | |
| 270 | + | |
| 271 | + if (nm.isQualified()) { | |
| 272 | + // Don't bother it is already qualified | |
| 273 | + if (tracing) env.dtExit("Imports.resolve: QUALIFIED " + nm); | |
| 274 | + return nm; | |
| 275 | + } | |
| 276 | + | |
| 277 | + if (checked <= 0) { | |
| 278 | + checked = 0; | |
| 279 | + resolve(env); | |
| 280 | + } | |
| 281 | + | |
| 282 | + // Check if it was imported before | |
| 283 | + Identifier className = (Identifier)classes.get(nm); | |
| 284 | + if (className != null) { | |
| 285 | + if (tracing) env.dtExit("Imports.resolve: PREVIOUSLY IMPORTED " + nm); | |
| 286 | + return className; | |
| 287 | + } | |
| 288 | + | |
| 289 | + // Note: the section below has changed a bit during the fix | |
| 290 | + // for bug 4093217. The current package is no longer grouped | |
| 291 | + // with the rest of the import-on-demands; it is now checked | |
| 292 | + // separately. Also, the list of import-on-demands is now | |
| 293 | + // guarranteed to be duplicate-free, so the code below can afford | |
| 294 | + // to be a bit simpler. | |
| 295 | + | |
| 296 | + // First we look in the current package. The current package | |
| 297 | + // is given precedence over the rest of the import-on-demands, | |
| 298 | + // which means, among other things, that a class in the current | |
| 299 | + // package cannot be ambiguous. | |
| 300 | + Identifier id = Identifier.lookup(currentPackage, nm); | |
| 301 | + if (importable(id, env)) { | |
| 302 | + className = id; | |
| 303 | + } else { | |
| 304 | + // If it isn't in the current package, try to find it in | |
| 305 | + // our import-on-demands. | |
| 306 | + Enumeration e = packages.elements(); | |
| 307 | + while (e.hasMoreElements()) { | |
| 308 | + IdentifierToken t = (IdentifierToken)e.nextElement(); | |
| 309 | + id = Identifier.lookup(t.getName(), nm); | |
| 310 | + | |
| 311 | + if (importable(id, env)) { | |
| 312 | + if (className == null) { | |
| 313 | + // We haven't found any other matching classes yet. | |
| 314 | + // Set className to what we've found and continue | |
| 315 | + // looking for an ambiguity. | |
| 316 | + className = id; | |
| 317 | + } else { | |
| 318 | + if (tracing) | |
| 319 | + env.dtExit("Imports.resolve: AMBIGUOUS " + nm); | |
| 320 | + | |
| 321 | + // We've found an ambiguity. | |
| 322 | + throw new AmbiguousClass(className, id); | |
| 323 | + } | |
| 324 | + } | |
| 325 | + } | |
| 326 | + } | |
| 327 | + | |
| 328 | + // Make sure a class was found | |
| 329 | + if (className == null) { | |
| 330 | + if (tracing) env.dtExit("Imports.resolve: NOT FOUND " + nm); | |
| 331 | + throw new ClassNotFound(nm); | |
| 332 | + } | |
| 333 | + | |
| 334 | + // Remember the binding | |
| 335 | + classes.put(nm, className); | |
| 336 | + if (tracing) env.dtExit("Imports.resolve: FIRST IMPORT " + nm); | |
| 337 | + return className; | |
| 338 | + } | |
| 339 | + | |
| 340 | + /** | |
| 341 | + * Check to see if 'id' names an importable class in `env'. | |
| 342 | + * This method was made public and static for utility. | |
| 343 | + */ | |
| 344 | + static public boolean importable(Identifier id, Environment env) { | |
| 345 | + if (!id.isInner()) { | |
| 346 | + return env.classExists(id); | |
| 347 | + } else if (!env.classExists(id.getTopName())) { | |
| 348 | + return false; | |
| 349 | + } else { | |
| 350 | + // load the top class and look inside it | |
| 351 | + try { | |
| 352 | + // There used to be a call to... | |
| 353 | + // env.getClassDeclaration(id.getTopName()); | |
| 354 | + // ...here. It has been replaced with the | |
| 355 | + // two statements below. These should be functionally | |
| 356 | + // the same except for the fact that | |
| 357 | + // getClassDefinitionNoCheck() does not call | |
| 358 | + // basicCheck(). This allows us to avoid a circular | |
| 359 | + // need to do basicChecking that can arise with | |
| 360 | + // certain patterns of importing and inheritance. | |
| 361 | + // This is a fix for a variant of bug 4086139. | |
| 362 | + // | |
| 363 | + // Note: the special case code in env.getClassDefinition() | |
| 364 | + // which handles inner class names is not replicated below. | |
| 365 | + // This should be okay, as we are looking up id.getTopName(), | |
| 366 | + // not id. | |
| 367 | + ClassDeclaration decl = | |
| 368 | + env.getClassDeclaration(id.getTopName()); | |
| 369 | + ClassDefinition c = | |
| 370 | + decl.getClassDefinitionNoCheck(env); | |
| 371 | + | |
| 372 | + return c.innerClassExists(id.getFlatName().getTail()); | |
| 373 | + } catch (ClassNotFound ee) { | |
| 374 | + return false; | |
| 375 | + } | |
| 376 | + } | |
| 377 | + } | |
| 378 | + | |
| 379 | + /** | |
| 380 | + * Suppose a resolve() call has failed. | |
| 381 | + * This routine can be used silently to give a reasonable | |
| 382 | + * default qualification (the current package) to the identifier. | |
| 383 | + * This decision is recorded for future reference. | |
| 384 | + */ | |
| 385 | + public synchronized Identifier forceResolve(Environment env, Identifier nm) { | |
| 386 | + if (nm.isQualified()) | |
| 387 | + return nm; | |
| 388 | + | |
| 389 | + Identifier className = (Identifier)classes.get(nm); | |
| 390 | + if (className != null) { | |
| 391 | + return className; | |
| 392 | + } | |
| 393 | + | |
| 394 | + className = Identifier.lookup(currentPackage, nm); | |
| 395 | + | |
| 396 | + classes.put(nm, className); | |
| 397 | + return className; | |
| 398 | + } | |
| 399 | + | |
| 400 | + /** | |
| 401 | + * Add a class import | |
| 402 | + */ | |
| 403 | + public synchronized void addClass(IdentifierToken t) { | |
| 404 | + singles.addElement(t); | |
| 405 | + } | |
| 406 | + // for compatibility | |
| 407 | + public void addClass(Identifier nm) throws AmbiguousClass { | |
| 408 | + addClass(new IdentifierToken(nm)); | |
| 409 | + } | |
| 410 | + | |
| 411 | + /** | |
| 412 | + * Add a package import, or perhaps an inner class scope. | |
| 413 | + * Ignore any duplicate imports. | |
| 414 | + */ | |
| 415 | + public synchronized void addPackage(IdentifierToken t) { | |
| 416 | + final Identifier name = t.getName(); | |
| 417 | + | |
| 418 | + // If this is a duplicate import for the current package, | |
| 419 | + // ignore it. | |
| 420 | + if (name == currentPackage) { | |
| 421 | + return; | |
| 422 | + } | |
| 423 | + | |
| 424 | + // If this is a duplicate of a package which has already been | |
| 425 | + // added to the list, ignore it. | |
| 426 | + final int size = packages.size(); | |
| 427 | + for (int i = 0; i < size; i++) { | |
| 428 | + if (name == ((IdentifierToken)packages.elementAt(i)).getName()) { | |
| 429 | + return; | |
| 430 | + } | |
| 431 | + } | |
| 432 | + | |
| 433 | + // Add the package to the list. | |
| 434 | + packages.addElement(t); | |
| 435 | + } | |
| 436 | + // for compatibility | |
| 437 | + public void addPackage(Identifier id) { | |
| 438 | + addPackage(new IdentifierToken(id)); | |
| 439 | + } | |
| 440 | + | |
| 441 | + /** | |
| 442 | + * Specify the current package with an IdentifierToken. | |
| 443 | + */ | |
| 444 | + public synchronized void setCurrentPackage(IdentifierToken t) { | |
| 445 | + currentPackage = t.getName(); | |
| 446 | + currentPackageWhere = t.getWhere(); | |
| 447 | + } | |
| 448 | + | |
| 449 | + /** | |
| 450 | + * Specify the current package | |
| 451 | + */ | |
| 452 | + public synchronized void setCurrentPackage(Identifier id) { | |
| 453 | + currentPackage = id; | |
| 454 | + } | |
| 455 | + | |
| 456 | + /** | |
| 457 | + * Report the current package | |
| 458 | + */ | |
| 459 | + public Identifier getCurrentPackage() { | |
| 460 | + return currentPackage; | |
| 461 | + } | |
| 462 | + | |
| 463 | + /** | |
| 464 | + * Return an unmodifiable list of IdentifierToken representing | |
| 465 | + * packages specified as imports. | |
| 466 | + */ | |
| 467 | + public List getImportedPackages() { | |
| 468 | + return Collections.unmodifiableList(packages); | |
| 469 | + } | |
| 470 | + | |
| 471 | + /** | |
| 472 | + * Return an unmodifiable list of IdentifierToken representing | |
| 473 | + * classes specified as imports. | |
| 474 | + */ | |
| 475 | + public List getImportedClasses() { | |
| 476 | + return Collections.unmodifiableList(singles); | |
| 477 | + } | |
| 478 | + | |
| 479 | + /** | |
| 480 | + * Extend an environment with my resolve() method. | |
| 481 | + */ | |
| 482 | + public Environment newEnvironment(Environment env) { | |
| 483 | + return new ImportEnvironment(env, this); | |
| 484 | + } | |
| 485 | +} | |
| 486 | + | |
| 487 | +final | |
| 488 | +class ImportEnvironment extends Environment { | |
| 489 | + Imports imports; | |
| 490 | + | |
| 491 | + ImportEnvironment(Environment env, Imports imports) { | |
| 492 | + super(env, env.getSource()); | |
| 493 | + this.imports = imports; | |
| 494 | + } | |
| 495 | + | |
| 496 | + public Identifier resolve(Identifier nm) throws ClassNotFound { | |
| 497 | + return imports.resolve(this, nm); | |
| 498 | + } | |
| 499 | + | |
| 500 | + public Imports getImports() { | |
| 501 | + return imports; | |
| 502 | + } | |
| 503 | +} | |
| @@ -0,0 +1,1007 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +import sun.tools.tree.Node; | |
| 29 | +import sun.tools.tree.Vset; | |
| 30 | +import sun.tools.tree.Expression; | |
| 31 | +import sun.tools.tree.Statement; | |
| 32 | +import sun.tools.tree.Context; | |
| 33 | +import sun.tools.asm.Assembler; | |
| 34 | +import java.io.PrintStream; | |
| 35 | +import java.util.Vector; | |
| 36 | +import java.util.Map; | |
| 37 | +import java.util.HashMap; | |
| 38 | + | |
| 39 | +/** | |
| 40 | + * This class defines a member of a Java class: | |
| 41 | + * a variable, a method, or an inner class. | |
| 42 | + * | |
| 43 | + * WARNING: The contents of this source file are not part of any | |
| 44 | + * supported API. Code that depends on them does so at its own risk: | |
| 45 | + * they are subject to change or removal without notice. | |
| 46 | + */ | |
| 47 | +public | |
| 48 | +class MemberDefinition implements Constants { | |
| 49 | + protected long where; | |
| 50 | + protected int modifiers; | |
| 51 | + protected Type type; | |
| 52 | + protected String documentation; | |
| 53 | + protected IdentifierToken expIds[]; | |
| 54 | + protected ClassDeclaration exp[]; | |
| 55 | + protected Node value; | |
| 56 | + protected ClassDefinition clazz; | |
| 57 | + protected Identifier name; | |
| 58 | + protected ClassDefinition innerClass; | |
| 59 | + protected MemberDefinition nextMember; | |
| 60 | + protected MemberDefinition nextMatch; | |
| 61 | + protected MemberDefinition accessPeer; | |
| 62 | + protected boolean superAccessMethod; | |
| 63 | + | |
| 64 | + /** | |
| 65 | + * Constructor | |
| 66 | + */ | |
| 67 | + public MemberDefinition(long where, ClassDefinition clazz, int modifiers, | |
| 68 | + Type type, Identifier name, | |
| 69 | + IdentifierToken expIds[], Node value) { | |
| 70 | + if (expIds == null) { | |
| 71 | + expIds = new IdentifierToken[0]; | |
| 72 | + } | |
| 73 | + this.where = where; | |
| 74 | + this.clazz = clazz; | |
| 75 | + this.modifiers = modifiers; | |
| 76 | + this.type = type; | |
| 77 | + this.name = name; | |
| 78 | + this.expIds = expIds; | |
| 79 | + this.value = value; | |
| 80 | + } | |
| 81 | + | |
| 82 | + /** | |
| 83 | + * Constructor for an inner class. | |
| 84 | + * Inner classes are represented as fields right along with | |
| 85 | + * variables and methods for simplicity of data structure, | |
| 86 | + * and to reflect properly the textual declaration order. | |
| 87 | + * <p> | |
| 88 | + * This constructor calls the generic constructor for this | |
| 89 | + * class, extracting all necessary values from the innerClass. | |
| 90 | + */ | |
| 91 | + public MemberDefinition(ClassDefinition innerClass) { | |
| 92 | + this(innerClass.getWhere(), | |
| 93 | + innerClass.getOuterClass(), | |
| 94 | + innerClass.getModifiers(), | |
| 95 | + innerClass.getType(), | |
| 96 | + innerClass.getName().getFlatName().getName(), | |
| 97 | + null, null); | |
| 98 | + this.innerClass = innerClass; | |
| 99 | + } | |
| 100 | + | |
| 101 | + /** | |
| 102 | + * A cache of previously created proxy members. Used to ensure | |
| 103 | + * uniqueness of proxy objects. See the makeProxyMember method | |
| 104 | + * defined below. | |
| 105 | + */ | |
| 106 | + static private Map proxyCache; | |
| 107 | + | |
| 108 | + /** | |
| 109 | + * Create a member which is externally the same as `field' but | |
| 110 | + * is defined in class `classDef'. This is used by code | |
| 111 | + * in sun.tools.tree.(MethodExpression,FieldExpression) as | |
| 112 | + * part of the fix for bug 4135692. | |
| 113 | + * | |
| 114 | + * Proxy members should not be added, ala addMember(), to classes. | |
| 115 | + * They are merely "stand-ins" to produce modified MethodRef | |
| 116 | + * constant pool entries during code generation. | |
| 117 | + * | |
| 118 | + * We keep a cache of previously created proxy members not to | |
| 119 | + * save time or space, but to ensure uniqueness of the proxy | |
| 120 | + * member for any (field,classDef) pair. If these are not made | |
| 121 | + * unique then we can end up generating duplicate MethodRef | |
| 122 | + * constant pool entries during code generation. | |
| 123 | + */ | |
| 124 | + public static MemberDefinition makeProxyMember(MemberDefinition field, | |
| 125 | + ClassDefinition classDef, | |
| 126 | + Environment env) { | |
| 127 | + | |
| 128 | + if (proxyCache == null) { | |
| 129 | + proxyCache = new HashMap(); | |
| 130 | + } | |
| 131 | + | |
| 132 | + String key = field.toString() + "@" + classDef.toString(); | |
| 133 | + // System.out.println("Key is : " + key); | |
| 134 | + MemberDefinition proxy = (MemberDefinition)proxyCache.get(key); | |
| 135 | + | |
| 136 | + if (proxy != null) | |
| 137 | + return proxy; | |
| 138 | + | |
| 139 | + proxy = new MemberDefinition(field.getWhere(), classDef, | |
| 140 | + field.getModifiers(), field.getType(), | |
| 141 | + field.getName(), field.getExceptionIds(), | |
| 142 | + null); | |
| 143 | + proxy.exp = field.getExceptions(env); | |
| 144 | + proxyCache.put(key, proxy); | |
| 145 | + | |
| 146 | + return proxy; | |
| 147 | + } | |
| 148 | + | |
| 149 | + /** | |
| 150 | + * Get the position in the input | |
| 151 | + */ | |
| 152 | + public final long getWhere() { | |
| 153 | + return where; | |
| 154 | + } | |
| 155 | + | |
| 156 | + /** | |
| 157 | + * Get the class declaration | |
| 158 | + */ | |
| 159 | + public final ClassDeclaration getClassDeclaration() { | |
| 160 | + return clazz.getClassDeclaration(); | |
| 161 | + } | |
| 162 | + | |
| 163 | + /** | |
| 164 | + * A stub. Subclasses can do more checking. | |
| 165 | + */ | |
| 166 | + public void resolveTypeStructure(Environment env) { | |
| 167 | + } | |
| 168 | + | |
| 169 | + /** | |
| 170 | + * Get the class declaration in which the field is actually defined | |
| 171 | + */ | |
| 172 | + public ClassDeclaration getDefiningClassDeclaration() { | |
| 173 | + return getClassDeclaration(); | |
| 174 | + } | |
| 175 | + | |
| 176 | + /** | |
| 177 | + * Get the class definition | |
| 178 | + */ | |
| 179 | + public final ClassDefinition getClassDefinition() { | |
| 180 | + return clazz; | |
| 181 | + } | |
| 182 | + | |
| 183 | + /** | |
| 184 | + * Get the field's top-level enclosing class | |
| 185 | + */ | |
| 186 | + public final ClassDefinition getTopClass() { | |
| 187 | + return clazz.getTopClass(); | |
| 188 | + } | |
| 189 | + | |
| 190 | + /** | |
| 191 | + * Get the field's modifiers | |
| 192 | + */ | |
| 193 | + public final int getModifiers() { | |
| 194 | + return modifiers; | |
| 195 | + } | |
| 196 | + public final void subModifiers(int mod) { | |
| 197 | + modifiers &= ~mod; | |
| 198 | + } | |
| 199 | + public final void addModifiers(int mod) { | |
| 200 | + modifiers |= mod; | |
| 201 | + } | |
| 202 | + | |
| 203 | + /** | |
| 204 | + * Get the field's type | |
| 205 | + */ | |
| 206 | + public final Type getType() { | |
| 207 | + return type; | |
| 208 | + } | |
| 209 | + | |
| 210 | + /** | |
| 211 | + * Get the field's name | |
| 212 | + */ | |
| 213 | + public final Identifier getName() { | |
| 214 | + return name; | |
| 215 | + } | |
| 216 | + | |
| 217 | + /** | |
| 218 | + * Get arguments (a vector of LocalMember) | |
| 219 | + */ | |
| 220 | + public Vector getArguments() { | |
| 221 | + return isMethod() ? new Vector() : null; | |
| 222 | + } | |
| 223 | + | |
| 224 | + /** | |
| 225 | + * Get the exceptions that are thrown by this method. | |
| 226 | + */ | |
| 227 | + public ClassDeclaration[] getExceptions(Environment env) { | |
| 228 | + if (expIds != null && exp == null) { | |
| 229 | + if (expIds.length == 0) | |
| 230 | + exp = new ClassDeclaration[0]; | |
| 231 | + else | |
| 232 | + // we should have translated this already! | |
| 233 | + throw new CompilerError("getExceptions "+this); | |
| 234 | + } | |
| 235 | + return exp; | |
| 236 | + } | |
| 237 | + | |
| 238 | + public final IdentifierToken[] getExceptionIds() { | |
| 239 | + return expIds; | |
| 240 | + } | |
| 241 | + | |
| 242 | + /** | |
| 243 | + * Get an inner class. | |
| 244 | + */ | |
| 245 | + public ClassDefinition getInnerClass() { | |
| 246 | + return innerClass; | |
| 247 | + } | |
| 248 | + | |
| 249 | + /** | |
| 250 | + * Is this a synthetic field which holds a copy of, | |
| 251 | + * or reference to, a local variable or enclosing instance? | |
| 252 | + */ | |
| 253 | + public boolean isUplevelValue() { | |
| 254 | + if (!isSynthetic() || !isVariable() || isStatic()) { | |
| 255 | + return false; | |
| 256 | + } | |
| 257 | + String name = this.name.toString(); | |
| 258 | + return name.startsWith(prefixVal) | |
| 259 | + || name.toString().startsWith(prefixLoc) | |
| 260 | + || name.toString().startsWith(prefixThis); | |
| 261 | + } | |
| 262 | + | |
| 263 | + public boolean isAccessMethod() { | |
| 264 | + // This no longer works, because access methods | |
| 265 | + // for constructors do not use the standard naming | |
| 266 | + // scheme. | |
| 267 | + // return isSynthetic() && isMethod() | |
| 268 | + // && name.toString().startsWith(prefixAccess); | |
| 269 | + // Assume that a method is an access method if it has | |
| 270 | + // an access peer. NOTE: An access method will not be | |
| 271 | + // recognized as such until 'setAccessMethodTarget' has | |
| 272 | + // been called on it. | |
| 273 | + return isSynthetic() && isMethod() && (accessPeer != null); | |
| 274 | + } | |
| 275 | + | |
| 276 | + /** | |
| 277 | + * Is this a synthetic method which provides access to a | |
| 278 | + * visible private member? | |
| 279 | + */ | |
| 280 | + public MemberDefinition getAccessMethodTarget() { | |
| 281 | + if (isAccessMethod()) { | |
| 282 | + for (MemberDefinition f = accessPeer; f != null; f = f.accessPeer) { | |
| 283 | + // perhaps skip over another access for the same field | |
| 284 | + if (!f.isAccessMethod()) { | |
| 285 | + return f; | |
| 286 | + } | |
| 287 | + } | |
| 288 | + } | |
| 289 | + return null; | |
| 290 | + } | |
| 291 | + | |
| 292 | + | |
| 293 | + public void setAccessMethodTarget(MemberDefinition target) { | |
| 294 | + if (getAccessMethodTarget() != target) { | |
| 295 | + /*-------------------* | |
| 296 | + if (!isAccessMethod() || accessPeer != null || | |
| 297 | + target.accessPeer != null) { | |
| 298 | + throw new CompilerError("accessPeer"); | |
| 299 | + } | |
| 300 | + *-------------------*/ | |
| 301 | + if (accessPeer != null || target.accessPeer != null) { | |
| 302 | + throw new CompilerError("accessPeer"); | |
| 303 | + } | |
| 304 | + accessPeer = target; | |
| 305 | + } | |
| 306 | + } | |
| 307 | + | |
| 308 | + /** | |
| 309 | + * If this method is a getter for a private field, return the setter. | |
| 310 | + */ | |
| 311 | + public MemberDefinition getAccessUpdateMember() { | |
| 312 | + if (isAccessMethod()) { | |
| 313 | + for (MemberDefinition f = accessPeer; f != null; f = f.accessPeer) { | |
| 314 | + if (f.isAccessMethod()) { | |
| 315 | + return f; | |
| 316 | + } | |
| 317 | + } | |
| 318 | + } | |
| 319 | + return null; | |
| 320 | + } | |
| 321 | + | |
| 322 | + public void setAccessUpdateMember(MemberDefinition updater) { | |
| 323 | + if (getAccessUpdateMember() != updater) { | |
| 324 | + if (!isAccessMethod() || | |
| 325 | + updater.getAccessMethodTarget() != getAccessMethodTarget()) { | |
| 326 | + throw new CompilerError("accessPeer"); | |
| 327 | + } | |
| 328 | + updater.accessPeer = accessPeer; | |
| 329 | + accessPeer = updater; | |
| 330 | + } | |
| 331 | + } | |
| 332 | + | |
| 333 | + /** | |
| 334 | + * Is this an access method for a field selection or method call | |
| 335 | + * of the form '...super.foo' or '...super.foo()'? | |
| 336 | + */ | |
| 337 | + public final boolean isSuperAccessMethod() { | |
| 338 | + return superAccessMethod; | |
| 339 | + } | |
| 340 | + | |
| 341 | + /** | |
| 342 | + * Mark this member as an access method for a field selection | |
| 343 | + * or method call via the 'super' keyword. | |
| 344 | + */ | |
| 345 | + public final void setIsSuperAccessMethod(boolean b) { | |
| 346 | + superAccessMethod = b; | |
| 347 | + } | |
| 348 | + | |
| 349 | + /** | |
| 350 | + * Tell if this is a final variable without an initializer. | |
| 351 | + * Such variables are subject to definite single assignment. | |
| 352 | + */ | |
| 353 | + public final boolean isBlankFinal() { | |
| 354 | + return isFinal() && !isSynthetic() && getValue() == null; | |
| 355 | + } | |
| 356 | + | |
| 357 | + public boolean isNeverNull() { | |
| 358 | + if (isUplevelValue()) { | |
| 359 | + // loc$x and this$C are never null | |
| 360 | + return !name.toString().startsWith(prefixVal); | |
| 361 | + } | |
| 362 | + return false; | |
| 363 | + } | |
| 364 | + | |
| 365 | + /** | |
| 366 | + * Get the field's final value (may return null) | |
| 367 | + */ | |
| 368 | + public Node getValue(Environment env) throws ClassNotFound { | |
| 369 | + return value; | |
| 370 | + } | |
| 371 | + public final Node getValue() { | |
| 372 | + return value; | |
| 373 | + } | |
| 374 | + public final void setValue(Node value) { | |
| 375 | + this.value = value; | |
| 376 | + } | |
| 377 | + public Object getInitialValue() { | |
| 378 | + return null; | |
| 379 | + } | |
| 380 | + | |
| 381 | + /** | |
| 382 | + * Get the next field or the next match | |
| 383 | + */ | |
| 384 | + public final MemberDefinition getNextMember() { | |
| 385 | + return nextMember; | |
| 386 | + } | |
| 387 | + public final MemberDefinition getNextMatch() { | |
| 388 | + return nextMatch; | |
| 389 | + } | |
| 390 | + | |
| 391 | + /** | |
| 392 | + * Get the field's documentation | |
| 393 | + */ | |
| 394 | + public String getDocumentation() { | |
| 395 | + return documentation; | |
| 396 | + } | |
| 397 | + | |
| 398 | + /** | |
| 399 | + * Request a check of the field definition. | |
| 400 | + */ | |
| 401 | + public void check(Environment env) throws ClassNotFound { | |
| 402 | + } | |
| 403 | + | |
| 404 | + /** | |
| 405 | + * Really check the field definition. | |
| 406 | + */ | |
| 407 | + public Vset check(Environment env, Context ctx, Vset vset) throws ClassNotFound { | |
| 408 | + return vset; | |
| 409 | + } | |
| 410 | + | |
| 411 | + /** | |
| 412 | + * Generate code | |
| 413 | + */ | |
| 414 | + public void code(Environment env, Assembler asm) throws ClassNotFound { | |
| 415 | + throw new CompilerError("code"); | |
| 416 | + } | |
| 417 | + public void codeInit(Environment env, Context ctx, Assembler asm) throws ClassNotFound { | |
| 418 | + throw new CompilerError("codeInit"); | |
| 419 | + } | |
| 420 | + | |
| 421 | + /** | |
| 422 | + * Tells whether to report a deprecation error for this field. | |
| 423 | + */ | |
| 424 | + public boolean reportDeprecated(Environment env) { | |
| 425 | + return (isDeprecated() || clazz.reportDeprecated(env)); | |
| 426 | + } | |
| 427 | + | |
| 428 | + /** | |
| 429 | + * Check if a field can reach another field (only considers | |
| 430 | + * forward references, not the access modifiers). | |
| 431 | + */ | |
| 432 | + public final boolean canReach(Environment env, MemberDefinition f) { | |
| 433 | + if (f.isLocal() || !f.isVariable() || !(isVariable() || isInitializer())) | |
| 434 | + return true; | |
| 435 | + if ((getClassDeclaration().equals(f.getClassDeclaration())) && | |
| 436 | + (isStatic() == f.isStatic())) { | |
| 437 | + // They are located in the same class, and are either both | |
| 438 | + // static or both non-static. Check the initialization order. | |
| 439 | + while (((f = f.getNextMember()) != null) && (f != this)); | |
| 440 | + return f != null; | |
| 441 | + } | |
| 442 | + return true; | |
| 443 | + } | |
| 444 | + | |
| 445 | + //----------------------------------------------------------------- | |
| 446 | + // The code in this section is intended to test certain kinds of | |
| 447 | + // compatibility between methods. There are two kinds of compatibility | |
| 448 | + // that the compiler may need to test. The first is whether one | |
| 449 | + // method can legally override another. The second is whether two | |
| 450 | + // method definitions can legally coexist. We use the word `meet' | |
| 451 | + // to mean the intersection of two legally coexisting methods. | |
| 452 | + // For more information on these kinds of compatibility, see the | |
| 453 | + // comments/code for checkOverride() and checkMeet() below. | |
| 454 | + | |
| 455 | + /** | |
| 456 | + * Constants used by getAccessLevel() to represent the access | |
| 457 | + * modifiers as numbers. | |
| 458 | + */ | |
| 459 | + static final int PUBLIC_ACCESS = 1; | |
| 460 | + static final int PROTECTED_ACCESS = 2; | |
| 461 | + static final int PACKAGE_ACCESS = 3; | |
| 462 | + static final int PRIVATE_ACCESS = 4; | |
| 463 | + | |
| 464 | + /** | |
| 465 | + * Return the access modifier of this member as a number. The idea | |
| 466 | + * is that this number may be used to check properties like "the | |
| 467 | + * access modifier of x is more restrictive than the access | |
| 468 | + * modifier of y" with a simple inequality test: | |
| 469 | + * "x.getAccessLevel() > y.getAccessLevel. | |
| 470 | + * | |
| 471 | + * This is an internal utility method. | |
| 472 | + */ | |
| 473 | + private int getAccessLevel() { | |
| 474 | + // Could just compute this once instead of recomputing. | |
| 475 | + // Check to see if this is worth it. | |
| 476 | + if (isPublic()) { | |
| 477 | + return PUBLIC_ACCESS; | |
| 478 | + } else if (isProtected()) { | |
| 479 | + return PROTECTED_ACCESS; | |
| 480 | + } else if (isPackagePrivate()) { | |
| 481 | + return PACKAGE_ACCESS; | |
| 482 | + } else if (isPrivate()) { | |
| 483 | + return PRIVATE_ACCESS; | |
| 484 | + } else { | |
| 485 | + throw new CompilerError("getAccessLevel()"); | |
| 486 | + } | |
| 487 | + } | |
| 488 | + | |
| 489 | + /** | |
| 490 | + * Munge our error message to report whether the override conflict | |
| 491 | + * came from an inherited method or a declared method. | |
| 492 | + */ | |
| 493 | + private void reportError(Environment env, String errorString, | |
| 494 | + ClassDeclaration clazz, | |
| 495 | + MemberDefinition method) { | |
| 496 | + | |
| 497 | + if (clazz == null) { | |
| 498 | + // For example: | |
| 499 | + // "Instance method BLAH inherited from CLASSBLAH1 cannot be | |
| 500 | + // overridden by the static method declared in CLASSBLAH2." | |
| 501 | + env.error(getWhere(), errorString, | |
| 502 | + this, getClassDeclaration(), | |
| 503 | + method.getClassDeclaration()); | |
| 504 | + } else { | |
| 505 | + // For example: | |
| 506 | + // "In CLASSBLAH1, instance method BLAH inherited from CLASSBLAH2 | |
| 507 | + // cannot be overridden by the static method inherited from | |
| 508 | + // CLASSBLAH3." | |
| 509 | + env.error(clazz.getClassDefinition().getWhere(), | |
| 510 | + //"inherit." + errorString, | |
| 511 | + errorString, | |
| 512 | + //clazz, | |
| 513 | + this, getClassDeclaration(), | |
| 514 | + method.getClassDeclaration()); | |
| 515 | + } | |
| 516 | + } | |
| 517 | + | |
| 518 | + /** | |
| 519 | + * Convenience method to see if two methods return the same type | |
| 520 | + */ | |
| 521 | + public boolean sameReturnType(MemberDefinition method) { | |
| 522 | + // Make sure both are methods. | |
| 523 | + if (!isMethod() || !method.isMethod()) { | |
| 524 | + throw new CompilerError("sameReturnType: not method"); | |
| 525 | + } | |
| 526 | + | |
| 527 | + Type myReturnType = getType().getReturnType(); | |
| 528 | + Type yourReturnType = method.getType().getReturnType(); | |
| 529 | + | |
| 530 | + return (myReturnType == yourReturnType); | |
| 531 | + } | |
| 532 | + | |
| 533 | + /** | |
| 534 | + * Check to see if `this' can override/hide `method'. Caller is | |
| 535 | + * responsible for verifying that `method' has the same signature | |
| 536 | + * as `this'. Caller is also responsible for verifying that | |
| 537 | + * `method' is visible to the class where this override is occurring. | |
| 538 | + * This method is called for the case when class B extends A and both | |
| 539 | + * A and B define some method. | |
| 540 | + * <pre> | |
| 541 | + * A - void foo() throws e1 | |
| 542 | + * | | |
| 543 | + * | | |
| 544 | + * B - void foo() throws e2 | |
| 545 | + * </pre> | |
| 546 | + */ | |
| 547 | + public boolean checkOverride(Environment env, MemberDefinition method) { | |
| 548 | + return checkOverride(env, method, null); | |
| 549 | + } | |
| 550 | + | |
| 551 | + /** | |
| 552 | + * Checks whether `this' can override `method'. It `clazz' is | |
| 553 | + * null, it reports the errors in the class where `this' is | |
| 554 | + * declared. If `clazz' is not null, it reports the error in `clazz'. | |
| 555 | + */ | |
| 556 | + private boolean checkOverride(Environment env, | |
| 557 | + MemberDefinition method, | |
| 558 | + ClassDeclaration clazz) { | |
| 559 | + // This section of code is largely based on section 8.4.6.3 | |
| 560 | + // of the JLS. | |
| 561 | + | |
| 562 | + boolean success = true; | |
| 563 | + | |
| 564 | + // Sanity | |
| 565 | + if (!isMethod()) { | |
| 566 | + throw new CompilerError("checkOverride(), expected method"); | |
| 567 | + } | |
| 568 | + | |
| 569 | + // Suppress checks for synthetic methods, as the compiler presumably | |
| 570 | + // knows what it is doing, e.g., access methods. | |
| 571 | + if (isSynthetic()) { | |
| 572 | + // Sanity check: We generally do not intend for one synthetic | |
| 573 | + // method to override another, though hiding of static members | |
| 574 | + // is expected. This check may need to be changed if new uses | |
| 575 | + // of synthetic methods are devised. | |
| 576 | + // | |
| 577 | + // Query: this code was copied from elsewhere. What | |
| 578 | + // exactly is the role of the !isStatic() in the test? | |
| 579 | + if (method.isFinal() || | |
| 580 | + (!method.isConstructor() && | |
| 581 | + !method.isStatic() && !isStatic())) { | |
| 582 | + //////////////////////////////////////////////////////////// | |
| 583 | + // NMG 2003-01-28 removed the following test because it is | |
| 584 | + // invalidated by bridge methods inserted by the "generic" | |
| 585 | + // (1.5) Java compiler. In 1.5, this code is used, | |
| 586 | + // indirectly, by rmic | |
| 587 | + //////////////////////////////////////////////////////////// | |
| 588 | + // throw new CompilerError("checkOverride() synthetic"); | |
| 589 | + //////////////////////////////////////////////////////////// | |
| 590 | + } | |
| 591 | + | |
| 592 | + // We trust the compiler. (Ha!) We're done checking. | |
| 593 | + return true; | |
| 594 | + } | |
| 595 | + | |
| 596 | + // Our caller should have verified that the method had the | |
| 597 | + // same signature. | |
| 598 | + if (getName() != method.getName() || | |
| 599 | + !getType().equalArguments(method.getType())) { | |
| 600 | + | |
| 601 | + throw new CompilerError("checkOverride(), signature mismatch"); | |
| 602 | + } | |
| 603 | + | |
| 604 | + // It is forbidden to `override' a static method with an instance | |
| 605 | + // method. | |
| 606 | + if (method.isStatic() && !isStatic()) { | |
| 607 | + reportError(env, "override.static.with.instance", clazz, method); | |
| 608 | + success = false; | |
| 609 | + } | |
| 610 | + | |
| 611 | + // It is forbidden to `hide' an instance method with a static | |
| 612 | + // method. | |
| 613 | + if (!method.isStatic() && isStatic()) { | |
| 614 | + reportError(env, "hide.instance.with.static", clazz, method); | |
| 615 | + success = false; | |
| 616 | + } | |
| 617 | + | |
| 618 | + // We cannot override a final method. | |
| 619 | + if (method.isFinal()) { | |
| 620 | + reportError(env, "override.final.method", clazz, method); | |
| 621 | + success = false; | |
| 622 | + } | |
| 623 | + | |
| 624 | + // Give a warning when we override a deprecated method with | |
| 625 | + // a non-deprecated one. | |
| 626 | + // | |
| 627 | + // We bend over backwards to suppress this warning if | |
| 628 | + // the `method' has not been already compiled or | |
| 629 | + // `this' has been already compiled. | |
| 630 | + if (method.reportDeprecated(env) && !isDeprecated() | |
| 631 | + && this instanceof sun.tools.javac.SourceMember) { | |
| 632 | + reportError(env, "warn.override.is.deprecated", | |
| 633 | + clazz, method); | |
| 634 | + } | |
| 635 | + | |
| 636 | + // Visibility may not be more restrictive | |
| 637 | + if (getAccessLevel() > method.getAccessLevel()) { | |
| 638 | + reportError(env, "override.more.restrictive", clazz, method); | |
| 639 | + success = false; | |
| 640 | + } | |
| 641 | + | |
| 642 | + // Return type equality | |
| 643 | + if (!sameReturnType(method)) { | |
| 644 | + //////////////////////////////////////////////////////////// | |
| 645 | + // PCJ 2003-07-30 removed the following error because it is | |
| 646 | + // invalidated by the covariant return type feature of the | |
| 647 | + // 1.5 compiler. The resulting check is now much looser | |
| 648 | + // than the actual 1.5 language spec, but that should be OK | |
| 649 | + // because this code is only still used by rmic. See 4892308. | |
| 650 | + //////////////////////////////////////////////////////////// | |
| 651 | + // reportError(env, "override.different.return", clazz, method); | |
| 652 | + // success = false; | |
| 653 | + //////////////////////////////////////////////////////////// | |
| 654 | + } | |
| 655 | + | |
| 656 | + // Exception agreeement | |
| 657 | + if (!exceptionsFit(env, method)) { | |
| 658 | + reportError(env, "override.incompatible.exceptions", | |
| 659 | + clazz, method); | |
| 660 | + success = false; | |
| 661 | + } | |
| 662 | + | |
| 663 | + return success; | |
| 664 | + } | |
| 665 | + | |
| 666 | + /** | |
| 667 | + * Check to see if two method definitions are compatible, that is | |
| 668 | + * do they have a `meet'. The meet of two methods is essentially | |
| 669 | + * and `intersection' of | |
| 670 | + * two methods. This method is called when some class C inherits | |
| 671 | + * declarations for some method foo from two parents (superclass, | |
| 672 | + * interfaces) but it does not, itself, have a declaration of foo. | |
| 673 | + * Caller is responsible for making sure that both methods are | |
| 674 | + * indeed visible in clazz. | |
| 675 | + * <pre> | |
| 676 | + * A - void foo() throws e1 | |
| 677 | + * \ | |
| 678 | + * \ B void foo() throws e2 | |
| 679 | + * \ / | |
| 680 | + * \ / | |
| 681 | + * C | |
| 682 | + * </pre> | |
| 683 | + */ | |
| 684 | + public boolean checkMeet(Environment env, | |
| 685 | + MemberDefinition method, | |
| 686 | + ClassDeclaration clazz) { | |
| 687 | + // This section of code is largely based on Section 8.4.6 | |
| 688 | + // and 9.4.1 of the JLS. | |
| 689 | + | |
| 690 | + // Sanity | |
| 691 | + if (!isMethod()) { | |
| 692 | + throw new CompilerError("checkMeet(), expected method"); | |
| 693 | + } | |
| 694 | + | |
| 695 | + // Check for both non-abstract. | |
| 696 | + if (!isAbstract() && !method.isAbstract()) { | |
| 697 | + throw new CompilerError("checkMeet(), no abstract method"); | |
| 698 | + } | |
| 699 | + | |
| 700 | + // If either method is non-abstract, then we need to check that | |
| 701 | + // the abstract method can be properly overridden. We call | |
| 702 | + // the checkOverride method to check this and generate any errors. | |
| 703 | + // This test must follow the previous test. | |
| 704 | + else if (!isAbstract()) { | |
| 705 | + return checkOverride(env, method, clazz); | |
| 706 | + } else if (!method.isAbstract()) { | |
| 707 | + return method.checkOverride(env, this, clazz); | |
| 708 | + } | |
| 709 | + | |
| 710 | + // Both methods are abstract. | |
| 711 | + | |
| 712 | + // Our caller should have verified that the method has the | |
| 713 | + // same signature. | |
| 714 | + if (getName() != method.getName() || | |
| 715 | + !getType().equalArguments(method.getType())) { | |
| 716 | + | |
| 717 | + throw new CompilerError("checkMeet(), signature mismatch"); | |
| 718 | + } | |
| 719 | + | |
| 720 | + // Check for return type equality | |
| 721 | + if (!sameReturnType(method)) { | |
| 722 | + // More args? | |
| 723 | + env.error(clazz.getClassDefinition().getWhere(), | |
| 724 | + "meet.different.return", | |
| 725 | + this, this.getClassDeclaration(), | |
| 726 | + method.getClassDeclaration()); | |
| 727 | + return false; | |
| 728 | + } | |
| 729 | + | |
| 730 | + // We don't have to check visibility -- there always | |
| 731 | + // potentially exists a meet. Similarly with exceptions. | |
| 732 | + | |
| 733 | + // There does exist a meet. | |
| 734 | + return true; | |
| 735 | + } | |
| 736 | + | |
| 737 | + /** | |
| 738 | + * This method is meant to be used to determine if one of two inherited | |
| 739 | + * methods could override the other. Unlike checkOverride(), failure | |
| 740 | + * is not an error. This method is only meant to be called after | |
| 741 | + * checkMeet() has succeeded on the two methods. | |
| 742 | + * | |
| 743 | + * If you call couldOverride() without doing a checkMeet() first, then | |
| 744 | + * you are on your own. | |
| 745 | + */ | |
| 746 | + public boolean couldOverride(Environment env, | |
| 747 | + MemberDefinition method) { | |
| 748 | + | |
| 749 | + // Sanity | |
| 750 | + if (!isMethod()) { | |
| 751 | + throw new CompilerError("coulcOverride(), expected method"); | |
| 752 | + } | |
| 753 | + | |
| 754 | + // couldOverride() is only called with `this' and `method' both | |
| 755 | + // being inherited methods. Neither of them is defined in the | |
| 756 | + // class which we are currently working on. Even though an | |
| 757 | + // abstract method defined *in* a class can override a non-abstract | |
| 758 | + // method defined in a superclass, an abstract method inherited | |
| 759 | + // from an interface *never* can override a non-abstract method. | |
| 760 | + // This comment may sound odd, but that's the way inheritance is. | |
| 761 | + // The following check makes sure we aren't trying to override | |
| 762 | + // an inherited non-abstract definition with an abstract definition | |
| 763 | + // from an interface. | |
| 764 | + if (!method.isAbstract()) { | |
| 765 | + return false; | |
| 766 | + } | |
| 767 | + | |
| 768 | + // Visibility should be less restrictive | |
| 769 | + if (getAccessLevel() > method.getAccessLevel()) { | |
| 770 | + return false; | |
| 771 | + } | |
| 772 | + | |
| 773 | + // Exceptions | |
| 774 | + if (!exceptionsFit(env, method)) { | |
| 775 | + return false; | |
| 776 | + } | |
| 777 | + | |
| 778 | + // Potentially some deprecation warnings could be given here | |
| 779 | + // when we merge two abstract methods, one of which is deprecated. | |
| 780 | + // This is not currently reported. | |
| 781 | + | |
| 782 | + return true; | |
| 783 | + } | |
| 784 | + | |
| 785 | + /** | |
| 786 | + * Check to see if the exceptions of `this' fit within the | |
| 787 | + * exceptions of `method'. | |
| 788 | + */ | |
| 789 | + private boolean exceptionsFit(Environment env, | |
| 790 | + MemberDefinition method) { | |
| 791 | + ClassDeclaration e1[] = getExceptions(env); // my exceptions | |
| 792 | + ClassDeclaration e2[] = method.getExceptions(env); // parent's | |
| 793 | + | |
| 794 | + // This code is taken nearly verbatim from the old implementation | |
| 795 | + // of checkOverride() in SourceClass. | |
| 796 | + outer: | |
| 797 | + for (int i = 0 ; i < e1.length ; i++) { | |
| 798 | + try { | |
| 799 | + ClassDefinition c1 = e1[i].getClassDefinition(env); | |
| 800 | + for (int j = 0 ; j < e2.length ; j++) { | |
| 801 | + if (c1.subClassOf(env, e2[j])) { | |
| 802 | + continue outer; | |
| 803 | + } | |
| 804 | + } | |
| 805 | + if (c1.subClassOf(env, | |
| 806 | + env.getClassDeclaration(idJavaLangError))) | |
| 807 | + continue outer; | |
| 808 | + if (c1.subClassOf(env, | |
| 809 | + env.getClassDeclaration(idJavaLangRuntimeException))) | |
| 810 | + continue outer; | |
| 811 | + | |
| 812 | + // the throws was neither something declared by a parent, | |
| 813 | + // nor one of the ignorables. | |
| 814 | + return false; | |
| 815 | + | |
| 816 | + } catch (ClassNotFound ee) { | |
| 817 | + // We were unable to find one of the exceptions. | |
| 818 | + env.error(getWhere(), "class.not.found", | |
| 819 | + ee.name, method.getClassDeclaration()); | |
| 820 | + } | |
| 821 | + } | |
| 822 | + | |
| 823 | + // All of the exceptions `fit'. | |
| 824 | + return true; | |
| 825 | + } | |
| 826 | + | |
| 827 | + //----------------------------------------------------------------- | |
| 828 | + | |
| 829 | + /** | |
| 830 | + * Checks | |
| 831 | + */ | |
| 832 | + public final boolean isPublic() { | |
| 833 | + return (modifiers & M_PUBLIC) != 0; | |
| 834 | + } | |
| 835 | + public final boolean isPrivate() { | |
| 836 | + return (modifiers & M_PRIVATE) != 0; | |
| 837 | + } | |
| 838 | + public final boolean isProtected() { | |
| 839 | + return (modifiers & M_PROTECTED) != 0; | |
| 840 | + } | |
| 841 | + public final boolean isPackagePrivate() { | |
| 842 | + return (modifiers & (M_PUBLIC | M_PRIVATE | M_PROTECTED)) == 0; | |
| 843 | + } | |
| 844 | + public final boolean isFinal() { | |
| 845 | + return (modifiers & M_FINAL) != 0; | |
| 846 | + } | |
| 847 | + public final boolean isStatic() { | |
| 848 | + return (modifiers & M_STATIC) != 0; | |
| 849 | + } | |
| 850 | + public final boolean isSynchronized() { | |
| 851 | + return (modifiers & M_SYNCHRONIZED) != 0; | |
| 852 | + } | |
| 853 | + public final boolean isAbstract() { | |
| 854 | + return (modifiers & M_ABSTRACT) != 0; | |
| 855 | + } | |
| 856 | + public final boolean isNative() { | |
| 857 | + return (modifiers & M_NATIVE) != 0; | |
| 858 | + } | |
| 859 | + public final boolean isVolatile() { | |
| 860 | + return (modifiers & M_VOLATILE) != 0; | |
| 861 | + } | |
| 862 | + public final boolean isTransient() { | |
| 863 | + return (modifiers & M_TRANSIENT) != 0; | |
| 864 | + } | |
| 865 | + public final boolean isMethod() { | |
| 866 | + return type.isType(TC_METHOD); | |
| 867 | + } | |
| 868 | + public final boolean isVariable() { | |
| 869 | + return !type.isType(TC_METHOD) && innerClass == null; | |
| 870 | + } | |
| 871 | + public final boolean isSynthetic() { | |
| 872 | + return (modifiers & M_SYNTHETIC) != 0; | |
| 873 | + } | |
| 874 | + public final boolean isDeprecated() { | |
| 875 | + return (modifiers & M_DEPRECATED) != 0; | |
| 876 | + } | |
| 877 | + public final boolean isStrict() { | |
| 878 | + return (modifiers & M_STRICTFP) != 0; | |
| 879 | + } | |
| 880 | + public final boolean isInnerClass() { | |
| 881 | + return innerClass != null; | |
| 882 | + } | |
| 883 | + public final boolean isInitializer() { | |
| 884 | + return getName().equals(idClassInit); | |
| 885 | + } | |
| 886 | + public final boolean isConstructor() { | |
| 887 | + return getName().equals(idInit); | |
| 888 | + } | |
| 889 | + public boolean isLocal() { | |
| 890 | + return false; | |
| 891 | + } | |
| 892 | + public boolean isInlineable(Environment env, boolean fromFinal) throws ClassNotFound { | |
| 893 | + return (isStatic() || isPrivate() || isFinal() || isConstructor() || fromFinal) && | |
| 894 | + !(isSynchronized() || isNative()); | |
| 895 | + } | |
| 896 | + | |
| 897 | + /** | |
| 898 | + * Check if constant: Will it inline away to a constant? | |
| 899 | + */ | |
| 900 | + public boolean isConstant() { | |
| 901 | + if (isFinal() && isVariable() && value != null) { | |
| 902 | + try { | |
| 903 | + // If an infinite regress requeries this name, | |
| 904 | + // deny that it is a constant. | |
| 905 | + modifiers &= ~M_FINAL; | |
| 906 | + return ((Expression)value).isConstant(); | |
| 907 | + } finally { | |
| 908 | + modifiers |= M_FINAL; | |
| 909 | + } | |
| 910 | + } | |
| 911 | + return false; | |
| 912 | + } | |
| 913 | + | |
| 914 | + /** | |
| 915 | + * toString | |
| 916 | + */ | |
| 917 | + public String toString() { | |
| 918 | + Identifier name = getClassDefinition().getName(); | |
| 919 | + if (isInitializer()) { | |
| 920 | + return isStatic() ? "static {}" : "instance {}"; | |
| 921 | + } else if (isConstructor()) { | |
| 922 | + StringBuffer buf = new StringBuffer(); | |
| 923 | + buf.append(name); | |
| 924 | + buf.append('('); | |
| 925 | + Type argTypes[] = getType().getArgumentTypes(); | |
| 926 | + for (int i = 0 ; i < argTypes.length ; i++) { | |
| 927 | + if (i > 0) { | |
| 928 | + buf.append(','); | |
| 929 | + } | |
| 930 | + buf.append(argTypes[i].toString()); | |
| 931 | + } | |
| 932 | + buf.append(')'); | |
| 933 | + return buf.toString(); | |
| 934 | + } else if (isInnerClass()) { | |
| 935 | + return getInnerClass().toString(); | |
| 936 | + } | |
| 937 | + return type.typeString(getName().toString()); | |
| 938 | + } | |
| 939 | + | |
| 940 | + /** | |
| 941 | + * Print for debugging | |
| 942 | + */ | |
| 943 | + public void print(PrintStream out) { | |
| 944 | + if (isPublic()) { | |
| 945 | + out.print("public "); | |
| 946 | + } | |
| 947 | + if (isPrivate()) { | |
| 948 | + out.print("private "); | |
| 949 | + } | |
| 950 | + if (isProtected()) { | |
| 951 | + out.print("protected "); | |
| 952 | + } | |
| 953 | + if (isFinal()) { | |
| 954 | + out.print("final "); | |
| 955 | + } | |
| 956 | + if (isStatic()) { | |
| 957 | + out.print("static "); | |
| 958 | + } | |
| 959 | + if (isSynchronized()) { | |
| 960 | + out.print("synchronized "); | |
| 961 | + } | |
| 962 | + if (isAbstract()) { | |
| 963 | + out.print("abstract "); | |
| 964 | + } | |
| 965 | + if (isNative()) { | |
| 966 | + out.print("native "); | |
| 967 | + } | |
| 968 | + if (isVolatile()) { | |
| 969 | + out.print("volatile "); | |
| 970 | + } | |
| 971 | + if (isTransient()) { | |
| 972 | + out.print("transient "); | |
| 973 | + } | |
| 974 | + out.println(toString() + ";"); | |
| 975 | + } | |
| 976 | + | |
| 977 | + public void cleanup(Environment env) { | |
| 978 | + documentation = null; | |
| 979 | + if (isMethod() && value != null) { | |
| 980 | + int cost = 0; | |
| 981 | + if (isPrivate() || isInitializer()) { | |
| 982 | + value = Statement.empty; | |
| 983 | + } else if ((cost = | |
| 984 | + ((Statement)value) | |
| 985 | + .costInline(Statement.MAXINLINECOST, null, null)) | |
| 986 | + >= Statement.MAXINLINECOST) { | |
| 987 | + // will never be inlined | |
| 988 | + value = Statement.empty; | |
| 989 | + } else { | |
| 990 | + try { | |
| 991 | + if (!isInlineable(null, true)) { | |
| 992 | + value = Statement.empty; | |
| 993 | + } | |
| 994 | + } | |
| 995 | + catch (ClassNotFound ee) { } | |
| 996 | + } | |
| 997 | + if (value != Statement.empty && env.dump()) { | |
| 998 | + env.output("[after cleanup of " + getName() + ", " + | |
| 999 | + cost + " expression cost units remain]"); | |
| 1000 | + } | |
| 1001 | + } else if (isVariable()) { | |
| 1002 | + if (isPrivate() || !isFinal() || type.isType(TC_ARRAY)) { | |
| 1003 | + value = null; | |
| 1004 | + } | |
| 1005 | + } | |
| 1006 | + } | |
| 1007 | +} | |
| @@ -0,0 +1,278 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +import java.util.*; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * The MethodSet structure is used to store methods for a class. | |
| 32 | + * It maintains the invariant that it never stores two methods | |
| 33 | + * with the same signature. MethodSets are able to lookup | |
| 34 | + * all methods with a given name and the unique method with a given | |
| 35 | + * signature (name, args). | |
| 36 | + * | |
| 37 | + * WARNING: The contents of this source file are not part of any | |
| 38 | + * supported API. Code that depends on them does so at its own risk: | |
| 39 | + * they are subject to change or removal without notice. | |
| 40 | + */ | |
| 41 | + | |
| 42 | +public | |
| 43 | +class MethodSet { | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * A Map containing Lists of MemberDefinitions. The Lists | |
| 47 | + * contain methods which share the same name. | |
| 48 | + */ | |
| 49 | + private final Map lookupMap; | |
| 50 | + | |
| 51 | + /** | |
| 52 | + * The number of methods stored in the MethodSet. | |
| 53 | + */ | |
| 54 | + private int count; | |
| 55 | + | |
| 56 | + /** | |
| 57 | + * Is this MethodSet currently frozen? See freeze() for more details. | |
| 58 | + */ | |
| 59 | + private boolean frozen; | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * Creates a brand new MethodSet | |
| 63 | + */ | |
| 64 | + public MethodSet() { | |
| 65 | + frozen = false; | |
| 66 | + lookupMap = new HashMap(); | |
| 67 | + count = 0; | |
| 68 | + } | |
| 69 | + | |
| 70 | + /** | |
| 71 | + * Returns the number of distinct methods stored in the MethodSet. | |
| 72 | + */ | |
| 73 | + public int size() { | |
| 74 | + return count; | |
| 75 | + } | |
| 76 | + | |
| 77 | + /** | |
| 78 | + * Adds `method' to the MethodSet. No method of the same signature | |
| 79 | + * should be already defined. | |
| 80 | + */ | |
| 81 | + public void add(MemberDefinition method) { | |
| 82 | + // Check for late additions. | |
| 83 | + if (frozen) { | |
| 84 | + throw new CompilerError("add()"); | |
| 85 | + } | |
| 86 | + | |
| 87 | + // todo: Check for method?? | |
| 88 | + | |
| 89 | + Identifier name = method.getName(); | |
| 90 | + | |
| 91 | + // Get a List containing all methods of this name. | |
| 92 | + List methodList = (List) lookupMap.get(name); | |
| 93 | + | |
| 94 | + if (methodList == null) { | |
| 95 | + // There is no method with this name already. | |
| 96 | + // Create a List, and insert it into the hash. | |
| 97 | + methodList = new ArrayList(); | |
| 98 | + lookupMap.put(name, methodList); | |
| 99 | + } | |
| 100 | + | |
| 101 | + // Make sure that no method with the same signature has already | |
| 102 | + // been added to the MethodSet. | |
| 103 | + int size = methodList.size(); | |
| 104 | + for (int i = 0; i < size; i++) { | |
| 105 | + if (((MemberDefinition) methodList.get(i)) | |
| 106 | + .getType().equalArguments(method.getType())) { | |
| 107 | + throw new CompilerError("duplicate addition"); | |
| 108 | + } | |
| 109 | + } | |
| 110 | + | |
| 111 | + // We add the method to the appropriate list. | |
| 112 | + methodList.add(method); | |
| 113 | + count++; | |
| 114 | + } | |
| 115 | + | |
| 116 | + /** | |
| 117 | + * Adds `method' to the MethodSet, replacing any previous definition | |
| 118 | + * with the same signature. | |
| 119 | + */ | |
| 120 | + public void replace(MemberDefinition method) { | |
| 121 | + // Check for late additions. | |
| 122 | + if (frozen) { | |
| 123 | + throw new CompilerError("replace()"); | |
| 124 | + } | |
| 125 | + | |
| 126 | + // todo: Check for method?? | |
| 127 | + | |
| 128 | + Identifier name = method.getName(); | |
| 129 | + | |
| 130 | + // Get a List containing all methods of this name. | |
| 131 | + List methodList = (List) lookupMap.get(name); | |
| 132 | + | |
| 133 | + if (methodList == null) { | |
| 134 | + // There is no method with this name already. | |
| 135 | + // Create a List, and insert it into the hash. | |
| 136 | + methodList = new ArrayList(); | |
| 137 | + lookupMap.put(name, methodList); | |
| 138 | + } | |
| 139 | + | |
| 140 | + // Replace the element which has the same signature as | |
| 141 | + // `method'. | |
| 142 | + int size = methodList.size(); | |
| 143 | + for (int i = 0; i < size; i++) { | |
| 144 | + if (((MemberDefinition) methodList.get(i)) | |
| 145 | + .getType().equalArguments(method.getType())) { | |
| 146 | + methodList.set(i, method); | |
| 147 | + return; | |
| 148 | + } | |
| 149 | + } | |
| 150 | + | |
| 151 | + // We add the method to the appropriate list. | |
| 152 | + methodList.add(method); | |
| 153 | + count++; | |
| 154 | + } | |
| 155 | + | |
| 156 | + /** | |
| 157 | + * If the MethodSet contains a method with the same signature | |
| 158 | + * then lookup() returns it. Otherwise, this method returns null. | |
| 159 | + */ | |
| 160 | + public MemberDefinition lookupSig(Identifier name, Type type) { | |
| 161 | + // Go through all methods of the same name and see if any | |
| 162 | + // have the right signature. | |
| 163 | + Iterator matches = lookupName(name); | |
| 164 | + MemberDefinition candidate; | |
| 165 | + | |
| 166 | + while (matches.hasNext()) { | |
| 167 | + candidate = (MemberDefinition) matches.next(); | |
| 168 | + if (candidate.getType().equalArguments(type)) { | |
| 169 | + return candidate; | |
| 170 | + } | |
| 171 | + } | |
| 172 | + | |
| 173 | + // No match. | |
| 174 | + return null; | |
| 175 | + } | |
| 176 | + | |
| 177 | + /** | |
| 178 | + * Returns an Iterator of all methods contained in the | |
| 179 | + * MethodSet which have a given name. | |
| 180 | + */ | |
| 181 | + public Iterator lookupName(Identifier name) { | |
| 182 | + // Find the List containing all methods of this name, and | |
| 183 | + // return that List's Iterator. | |
| 184 | + List methodList = (List) lookupMap.get(name); | |
| 185 | + if (methodList == null) { | |
| 186 | + // If there is no method of this name, return a bogus, empty | |
| 187 | + // Iterator. | |
| 188 | + return Collections.emptyIterator(); | |
| 189 | + } | |
| 190 | + return methodList.iterator(); | |
| 191 | + } | |
| 192 | + | |
| 193 | + /** | |
| 194 | + * Returns an Iterator of all methods in the MethodSet | |
| 195 | + */ | |
| 196 | + public Iterator iterator() { | |
| 197 | + | |
| 198 | + //---------------------------------------------------------- | |
| 199 | + // The inner class MethodIterator is used to create our | |
| 200 | + // Iterator of all methods in the MethodSet. | |
| 201 | + class MethodIterator implements Iterator { | |
| 202 | + Iterator hashIter = lookupMap.values().iterator(); | |
| 203 | + Iterator listIter = Collections.emptyIterator(); | |
| 204 | + | |
| 205 | + public boolean hasNext() { | |
| 206 | + if (listIter.hasNext()) { | |
| 207 | + return true; | |
| 208 | + } else { | |
| 209 | + if (hashIter.hasNext()) { | |
| 210 | + listIter = ((List) hashIter.next()) | |
| 211 | + .iterator(); | |
| 212 | + | |
| 213 | + // The following should be always true. | |
| 214 | + if (listIter.hasNext()) { | |
| 215 | + return true; | |
| 216 | + } else { | |
| 217 | + throw new | |
| 218 | + CompilerError("iterator() in MethodSet"); | |
| 219 | + } | |
| 220 | + } | |
| 221 | + } | |
| 222 | + | |
| 223 | + // We've run out of Lists. | |
| 224 | + return false; | |
| 225 | + } | |
| 226 | + | |
| 227 | + public Object next() { | |
| 228 | + return listIter.next(); | |
| 229 | + } | |
| 230 | + | |
| 231 | + public void remove() { | |
| 232 | + throw new UnsupportedOperationException(); | |
| 233 | + } | |
| 234 | + } | |
| 235 | + // end MethodIterator | |
| 236 | + //---------------------------------------------------------- | |
| 237 | + | |
| 238 | + // A one-liner. | |
| 239 | + return new MethodIterator(); | |
| 240 | + } | |
| 241 | + | |
| 242 | + /** | |
| 243 | + * After freeze() is called, the MethodSet becomes (mostly) | |
| 244 | + * immutable. Any calls to add() or addMeet() lead to | |
| 245 | + * CompilerErrors. Note that the entries themselves are still | |
| 246 | + * (unfortunately) open for mischievous and wanton modification. | |
| 247 | + */ | |
| 248 | + public void freeze() { | |
| 249 | + frozen = true; | |
| 250 | + } | |
| 251 | + | |
| 252 | + /** | |
| 253 | + * Tells whether freeze() has been called on this MethodSet. | |
| 254 | + */ | |
| 255 | + public boolean isFrozen() { | |
| 256 | + return frozen; | |
| 257 | + } | |
| 258 | + | |
| 259 | + /** | |
| 260 | + * Returns a (big) string representation of this MethodSet | |
| 261 | + */ | |
| 262 | + public String toString() { | |
| 263 | + int len = size(); | |
| 264 | + StringBuffer buf = new StringBuffer(); | |
| 265 | + Iterator all = iterator(); | |
| 266 | + buf.append("{"); | |
| 267 | + | |
| 268 | + while (all.hasNext()) { | |
| 269 | + buf.append(all.next().toString()); | |
| 270 | + len--; | |
| 271 | + if (len > 0) { | |
| 272 | + buf.append(", "); | |
| 273 | + } | |
| 274 | + } | |
| 275 | + buf.append("}"); | |
| 276 | + return buf.toString(); | |
| 277 | + } | |
| 278 | +} | |
| @@ -0,0 +1,107 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This class represents an Java method type. | |
| 30 | + * It overrides the relevant methods in class Type. | |
| 31 | + * | |
| 32 | + * WARNING: The contents of this source file are not part of any | |
| 33 | + * supported API. Code that depends on them does so at its own risk: | |
| 34 | + * they are subject to change or removal without notice. | |
| 35 | + * | |
| 36 | + * @author Arthur van Hoff | |
| 37 | + */ | |
| 38 | +public final | |
| 39 | +class MethodType extends Type { | |
| 40 | + /** | |
| 41 | + * The return type. | |
| 42 | + */ | |
| 43 | + Type returnType; | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * The argument types. | |
| 47 | + */ | |
| 48 | + Type argTypes[]; | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * Construct a method type. Use Type.tMethod to create | |
| 52 | + * a new method type. | |
| 53 | + * @see Type.tMethod | |
| 54 | + */ | |
| 55 | + MethodType(String typeSig, Type returnType, Type argTypes[]) { | |
| 56 | + super(TC_METHOD, typeSig); | |
| 57 | + this.returnType = returnType; | |
| 58 | + this.argTypes = argTypes; | |
| 59 | + } | |
| 60 | + | |
| 61 | + public Type getReturnType() { | |
| 62 | + return returnType; | |
| 63 | + } | |
| 64 | + | |
| 65 | + public Type getArgumentTypes()[] { | |
| 66 | + return argTypes; | |
| 67 | + } | |
| 68 | + | |
| 69 | + public boolean equalArguments(Type t) { | |
| 70 | + if (t.typeCode != TC_METHOD) { | |
| 71 | + return false; | |
| 72 | + } | |
| 73 | + MethodType m = (MethodType)t; | |
| 74 | + if (argTypes.length != m.argTypes.length) { | |
| 75 | + return false; | |
| 76 | + } | |
| 77 | + for (int i = argTypes.length - 1 ; i >= 0 ; i--) { | |
| 78 | + if (argTypes[i] != m.argTypes[i]) { | |
| 79 | + return false; | |
| 80 | + } | |
| 81 | + } | |
| 82 | + return true; | |
| 83 | + } | |
| 84 | + | |
| 85 | + public int stackSize() { | |
| 86 | + int n = 0; | |
| 87 | + for (int i = 0 ; i < argTypes.length ; i++) { | |
| 88 | + n += argTypes[i].stackSize(); | |
| 89 | + } | |
| 90 | + return n; | |
| 91 | + } | |
| 92 | + | |
| 93 | + public String typeString(String id, boolean abbrev, boolean ret) { | |
| 94 | + StringBuffer buf = new StringBuffer(); | |
| 95 | + buf.append(id); | |
| 96 | + buf.append('('); | |
| 97 | + for (int i = 0 ; i < argTypes.length ; i++) { | |
| 98 | + if (i > 0) { | |
| 99 | + buf.append(", "); | |
| 100 | + } | |
| 101 | + buf.append(argTypes[i].typeString("", abbrev, ret)); | |
| 102 | + } | |
| 103 | + buf.append(')'); | |
| 104 | + | |
| 105 | + return ret ? getReturnType().typeString(buf.toString(), abbrev, ret) : buf.toString(); | |
| 106 | + } | |
| 107 | +} | |
| @@ -0,0 +1,161 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +import java.util.Enumeration; | |
| 29 | +import java.io.File; | |
| 30 | +import java.io.IOException; | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * This class is used to represent the classes in a package. | |
| 34 | + * | |
| 35 | + * WARNING: The contents of this source file are not part of any | |
| 36 | + * supported API. Code that depends on them does so at its own risk: | |
| 37 | + * they are subject to change or removal without notice. | |
| 38 | + */ | |
| 39 | +public | |
| 40 | +class Package { | |
| 41 | + /** | |
| 42 | + * The path which we use to locate source files. | |
| 43 | + */ | |
| 44 | + ClassPath sourcePath; | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * The path which we use to locate class (binary) files. | |
| 48 | + */ | |
| 49 | + ClassPath binaryPath; | |
| 50 | + | |
| 51 | + /** | |
| 52 | + * The path name of the package. | |
| 53 | + */ | |
| 54 | + String pkg; | |
| 55 | + | |
| 56 | + /** | |
| 57 | + * Create a package given a class path, and package name. | |
| 58 | + */ | |
| 59 | + public Package(ClassPath path, Identifier pkg) throws IOException { | |
| 60 | + this(path, path, pkg); | |
| 61 | + } | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * Create a package given a source path, binary path, and package | |
| 65 | + * name. | |
| 66 | + */ | |
| 67 | + public Package(ClassPath sourcePath, | |
| 68 | + ClassPath binaryPath, | |
| 69 | + Identifier pkg) | |
| 70 | + throws IOException { | |
| 71 | + if (pkg.isInner()) | |
| 72 | + pkg = Identifier.lookup(pkg.getQualifier(), pkg.getFlatName()); | |
| 73 | + this.sourcePath = sourcePath; | |
| 74 | + this.binaryPath = binaryPath; | |
| 75 | + this.pkg = pkg.toString().replace('.', File.separatorChar); | |
| 76 | + } | |
| 77 | + | |
| 78 | + /** | |
| 79 | + * Check if a class is defined in this package. | |
| 80 | + * (If it is an inner class name, it is assumed to exist | |
| 81 | + * only if its binary file exists. This is somewhat pessimistic.) | |
| 82 | + */ | |
| 83 | + public boolean classExists(Identifier className) { | |
| 84 | + return getBinaryFile(className) != null || | |
| 85 | + !className.isInner() && | |
| 86 | + getSourceFile(className) != null; | |
| 87 | + } | |
| 88 | + | |
| 89 | + /** | |
| 90 | + * Check if the package exists | |
| 91 | + */ | |
| 92 | + public boolean exists() { | |
| 93 | + // Look for the directory on our binary path. | |
| 94 | + ClassFile dir = binaryPath.getDirectory(pkg); | |
| 95 | + if (dir != null && dir.isDirectory()) { | |
| 96 | + return true; | |
| 97 | + } | |
| 98 | + | |
| 99 | + if (sourcePath != binaryPath) { | |
| 100 | + // Look for the directory on our source path. | |
| 101 | + dir = sourcePath.getDirectory(pkg); | |
| 102 | + if (dir != null && dir.isDirectory()) { | |
| 103 | + return true; | |
| 104 | + } | |
| 105 | + } | |
| 106 | + | |
| 107 | + /* Accommodate ZIP files without CEN entries for directories | |
| 108 | + * (packages): look on class path for at least one binary | |
| 109 | + * file or one source file with the right package prefix | |
| 110 | + */ | |
| 111 | + String prefix = pkg + File.separator; | |
| 112 | + | |
| 113 | + return binaryPath.getFiles(prefix, ".class").hasMoreElements() | |
| 114 | + || sourcePath.getFiles(prefix, ".java").hasMoreElements(); | |
| 115 | + } | |
| 116 | + | |
| 117 | + private String makeName(String fileName) { | |
| 118 | + return pkg.equals("") ? fileName : pkg + File.separator + fileName; | |
| 119 | + } | |
| 120 | + | |
| 121 | + /** | |
| 122 | + * Get the .class file of a class | |
| 123 | + */ | |
| 124 | + public ClassFile getBinaryFile(Identifier className) { | |
| 125 | + className = Type.mangleInnerType(className); | |
| 126 | + String fileName = className.toString() + ".class"; | |
| 127 | + return binaryPath.getFile(makeName(fileName)); | |
| 128 | + } | |
| 129 | + | |
| 130 | + /** | |
| 131 | + * Get the .java file of a class | |
| 132 | + */ | |
| 133 | + public ClassFile getSourceFile(Identifier className) { | |
| 134 | + // The source file of an inner class is that of its outer class. | |
| 135 | + className = className.getTopName(); | |
| 136 | + String fileName = className.toString() + ".java"; | |
| 137 | + return sourcePath.getFile(makeName(fileName)); | |
| 138 | + } | |
| 139 | + | |
| 140 | + public ClassFile getSourceFile(String fileName) { | |
| 141 | + if (fileName.endsWith(".java")) { | |
| 142 | + return sourcePath.getFile(makeName(fileName)); | |
| 143 | + } | |
| 144 | + return null; | |
| 145 | + } | |
| 146 | + | |
| 147 | + public Enumeration getSourceFiles() { | |
| 148 | + return sourcePath.getFiles(pkg, ".java"); | |
| 149 | + } | |
| 150 | + | |
| 151 | + public Enumeration getBinaryFiles() { | |
| 152 | + return binaryPath.getFiles(pkg, ".class"); | |
| 153 | + } | |
| 154 | + | |
| 155 | + public String toString() { | |
| 156 | + if (pkg.equals("")) { | |
| 157 | + return "unnamed package"; | |
| 158 | + } | |
| 159 | + return "package " + pkg; | |
| 160 | + } | |
| 161 | +} | |
| @@ -0,0 +1,2130 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +import sun.tools.tree.*; | |
| 29 | +import java.io.IOException; | |
| 30 | +import java.io.InputStream; | |
| 31 | +import java.util.Enumeration; | |
| 32 | +import java.util.Vector; | |
| 33 | + | |
| 34 | +/** | |
| 35 | + * This class is used to parse Java statements and expressions. | |
| 36 | + * The result is a parse tree.<p> | |
| 37 | + * | |
| 38 | + * This class implements an operator precedence parser. Errors are | |
| 39 | + * reported to the Environment object, if the error can't be | |
| 40 | + * resolved immediately, a SyntaxError exception is thrown.<p> | |
| 41 | + * | |
| 42 | + * Error recovery is implemented by catching SyntaxError exceptions | |
| 43 | + * and discarding input tokens until an input token is reached that | |
| 44 | + * is possibly a legal continuation.<p> | |
| 45 | + * | |
| 46 | + * The parse tree that is constructed represents the input | |
| 47 | + * exactly (no rewrites to simpler forms). This is important | |
| 48 | + * if the resulting tree is to be used for code formatting in | |
| 49 | + * a programming environment. Currently only documentation comments | |
| 50 | + * are retained.<p> | |
| 51 | + * | |
| 52 | + * The parsing algorithm does NOT use any type information. Changes | |
| 53 | + * in the type system do not affect the structure of the parse tree. | |
| 54 | + * This restriction does introduce an ambiguity an expression of the | |
| 55 | + * form: (e1) e2 is assumed to be a cast if e2 does not start with | |
| 56 | + * an operator. That means that (a) - b is interpreted as subtract | |
| 57 | + * b from a and not cast negative b to type a. However, if a is a | |
| 58 | + * simple type (byte, int, ...) then it is assumed to be a cast.<p> | |
| 59 | + * | |
| 60 | + * WARNING: The contents of this source file are not part of any | |
| 61 | + * supported API. Code that depends on them does so at its own risk: | |
| 62 | + * they are subject to change or removal without notice. | |
| 63 | + * | |
| 64 | + * @author Arthur van Hoff | |
| 65 | + */ | |
| 66 | + | |
| 67 | +public | |
| 68 | +class Parser extends Scanner implements ParserActions, Constants { | |
| 69 | + /** | |
| 70 | + * Create a parser | |
| 71 | + */ | |
| 72 | + protected Parser(Environment env, InputStream in) throws IOException { | |
| 73 | + super(env, in); | |
| 74 | + this.scanner = this; | |
| 75 | + this.actions = this; | |
| 76 | + } | |
| 77 | + | |
| 78 | + /** | |
| 79 | + * Create a parser, given a scanner. | |
| 80 | + */ | |
| 81 | + protected Parser(Scanner scanner) throws IOException { | |
| 82 | + super(scanner.env); | |
| 83 | + this.scanner = scanner; | |
| 84 | + ((Scanner)this).env = scanner.env; | |
| 85 | + ((Scanner)this).token = scanner.token; | |
| 86 | + ((Scanner)this).pos = scanner.pos; | |
| 87 | + this.actions = this; | |
| 88 | + } | |
| 89 | + | |
| 90 | + /** | |
| 91 | + * Create a parser, given a scanner and the semantic callback. | |
| 92 | + */ | |
| 93 | + public Parser(Scanner scanner, ParserActions actions) throws IOException { | |
| 94 | + this(scanner); | |
| 95 | + this.actions = actions; | |
| 96 | + } | |
| 97 | + | |
| 98 | + /** | |
| 99 | + * Usually <code>this.actions == (ParserActions)this</code>. | |
| 100 | + * However, a delegate scanner can produce tokens for this parser, | |
| 101 | + * in which case <code>(Scanner)this</code> is unused, | |
| 102 | + * except for <code>this.token</code> and <code>this.pos</code> | |
| 103 | + * instance variables which are filled from the real scanner | |
| 104 | + * by <code>this.scan()</code> and the constructor. | |
| 105 | + */ | |
| 106 | + ParserActions actions; | |
| 107 | + | |
| 108 | + // Note: The duplication of methods allows pre-1.1 classes to | |
| 109 | + // be binary compatible with the new version of the parser, | |
| 110 | + // which now passes IdentifierTokens to the semantics phase, | |
| 111 | + // rather than just Identifiers. This change is necessary, | |
| 112 | + // since the parser is no longer responsible for managing the | |
| 113 | + // resolution of type names. (That caused the "Vector" bug.) | |
| 114 | + // | |
| 115 | + // In a future release, the old "plain-Identifier" methods will | |
| 116 | + // go away, and the corresponding "IdentifierToken" methods | |
| 117 | + // may become abstract. | |
| 118 | + | |
| 119 | + /** | |
| 120 | + * package declaration | |
| 121 | + * @deprecated | |
| 122 | + */ | |
| 123 | + @Deprecated | |
| 124 | + public void packageDeclaration(long off, IdentifierToken nm) { | |
| 125 | + // By default, call the deprecated version. | |
| 126 | + // Any application must override one of the packageDeclaration methods. | |
| 127 | + packageDeclaration(off, nm.id); | |
| 128 | + } | |
| 129 | + /** | |
| 130 | + * @deprecated | |
| 131 | + */ | |
| 132 | + @Deprecated | |
| 133 | + protected void packageDeclaration(long off, Identifier nm) { | |
| 134 | + throw new RuntimeException("beginClass method is abstract"); | |
| 135 | + } | |
| 136 | + | |
| 137 | + /** | |
| 138 | + * import class | |
| 139 | + * @deprecated | |
| 140 | + */ | |
| 141 | + @Deprecated | |
| 142 | + public void importClass(long off, IdentifierToken nm) { | |
| 143 | + // By default, call the deprecated version. | |
| 144 | + // Any application must override one of the packageDeclaration methods. | |
| 145 | + importClass(off, nm.id); | |
| 146 | + } | |
| 147 | + /** | |
| 148 | + * @deprecated Use the version with the IdentifierToken arguments. | |
| 149 | + */ | |
| 150 | + @Deprecated | |
| 151 | + protected void importClass(long off, Identifier nm) { | |
| 152 | + throw new RuntimeException("importClass method is abstract"); | |
| 153 | + } | |
| 154 | + | |
| 155 | + /** | |
| 156 | + * import package | |
| 157 | + * @deprecated | |
| 158 | + */ | |
| 159 | + @Deprecated | |
| 160 | + public void importPackage(long off, IdentifierToken nm) { | |
| 161 | + // By default, call the deprecated version. | |
| 162 | + // Any application must override one of the importPackage methods. | |
| 163 | + importPackage(off, nm.id); | |
| 164 | + } | |
| 165 | + /** | |
| 166 | + * @deprecated Use the version with the IdentifierToken arguments. | |
| 167 | + */ | |
| 168 | + @Deprecated | |
| 169 | + protected void importPackage(long off, Identifier nm) { | |
| 170 | + throw new RuntimeException("importPackage method is abstract"); | |
| 171 | + } | |
| 172 | + | |
| 173 | + /** | |
| 174 | + * Define class | |
| 175 | + * @deprecated | |
| 176 | + */ | |
| 177 | + @Deprecated | |
| 178 | + public ClassDefinition beginClass(long off, String doc, | |
| 179 | + int mod, IdentifierToken nm, | |
| 180 | + IdentifierToken sup, | |
| 181 | + IdentifierToken impl[]) { | |
| 182 | + // By default, call the deprecated version. | |
| 183 | + // Any application must override one of the beginClass methods. | |
| 184 | + Identifier supId = (sup == null) ? null : sup.id; | |
| 185 | + Identifier implIds[] = null; | |
| 186 | + if (impl != null) { | |
| 187 | + implIds = new Identifier[impl.length]; | |
| 188 | + for (int i = 0; i < impl.length; i++) { | |
| 189 | + implIds[i] = impl[i].id; | |
| 190 | + } | |
| 191 | + } | |
| 192 | + beginClass(off, doc, mod, nm.id, supId, implIds); | |
| 193 | + return getCurrentClass(); | |
| 194 | + } | |
| 195 | + /** | |
| 196 | + * @deprecated Use the version with the IdentifierToken arguments. | |
| 197 | + */ | |
| 198 | + @Deprecated | |
| 199 | + protected void beginClass(long off, String doc, int mod, Identifier nm, | |
| 200 | + Identifier sup, Identifier impl[]) { | |
| 201 | + throw new RuntimeException("beginClass method is abstract"); | |
| 202 | + } | |
| 203 | + | |
| 204 | + /** | |
| 205 | + * Report the current class under construction. | |
| 206 | + * By default, it's a no-op which returns null. | |
| 207 | + * It may only be called before the corresponding endClass(). | |
| 208 | + */ | |
| 209 | + protected ClassDefinition getCurrentClass() { | |
| 210 | + return null; | |
| 211 | + } | |
| 212 | + | |
| 213 | + /** | |
| 214 | + * End class | |
| 215 | + * @deprecated | |
| 216 | + */ | |
| 217 | + @Deprecated | |
| 218 | + public void endClass(long off, ClassDefinition c) { | |
| 219 | + // By default, call the deprecated version. | |
| 220 | + // Any application must override one of the beginClass methods. | |
| 221 | + endClass(off, c.getName().getFlatName().getName()); | |
| 222 | + } | |
| 223 | + /** | |
| 224 | + * @deprecated Use the version with the IdentifierToken arguments. | |
| 225 | + */ | |
| 226 | + @Deprecated | |
| 227 | + protected void endClass(long off, Identifier nm) { | |
| 228 | + throw new RuntimeException("endClass method is abstract"); | |
| 229 | + } | |
| 230 | + | |
| 231 | + /** | |
| 232 | + * Define a field | |
| 233 | + * @deprecated | |
| 234 | + */ | |
| 235 | + @Deprecated | |
| 236 | + public void defineField(long where, ClassDefinition c, | |
| 237 | + String doc, int mod, Type t, | |
| 238 | + IdentifierToken nm, IdentifierToken args[], | |
| 239 | + IdentifierToken exp[], Node val) { | |
| 240 | + // By default, call the deprecated version. | |
| 241 | + // Any application must override one of the defineField methods. | |
| 242 | + Identifier argIds[] = null; | |
| 243 | + Identifier expIds[] = null; | |
| 244 | + if (args != null) { | |
| 245 | + argIds = new Identifier[args.length]; | |
| 246 | + for (int i = 0; i < args.length; i++) { | |
| 247 | + argIds[i] = args[i].id; | |
| 248 | + } | |
| 249 | + } | |
| 250 | + if (exp != null) { | |
| 251 | + expIds = new Identifier[exp.length]; | |
| 252 | + for (int i = 0; i < exp.length; i++) { | |
| 253 | + expIds[i] = exp[i].id; | |
| 254 | + } | |
| 255 | + } | |
| 256 | + defineField(where, doc, mod, t, nm.id, argIds, expIds, val); | |
| 257 | + } | |
| 258 | + | |
| 259 | + /** | |
| 260 | + * @deprecated Use the version with the IdentifierToken arguments. | |
| 261 | + */ | |
| 262 | + @Deprecated | |
| 263 | + protected void defineField(long where, String doc, int mod, Type t, | |
| 264 | + Identifier nm, Identifier args[], | |
| 265 | + Identifier exp[], Node val) { | |
| 266 | + throw new RuntimeException("defineField method is abstract"); | |
| 267 | + } | |
| 268 | + | |
| 269 | + /* | |
| 270 | + * A growable array of nodes. It is used as a growable | |
| 271 | + * buffer to hold argument lists and expression lists. | |
| 272 | + * I'm not using Vector to make it more efficient. | |
| 273 | + */ | |
| 274 | + private Node args[] = new Node[32]; | |
| 275 | + protected int argIndex = 0; | |
| 276 | + | |
| 277 | + protected final void addArgument(Node n) { | |
| 278 | + if (argIndex == args.length) { | |
| 279 | + Node newArgs[] = new Node[args.length * 2]; | |
| 280 | + System.arraycopy(args, 0, newArgs, 0, args.length); | |
| 281 | + args = newArgs; | |
| 282 | + } | |
| 283 | + args[argIndex++] = n; | |
| 284 | + } | |
| 285 | + protected final Expression exprArgs(int index)[] { | |
| 286 | + Expression e[] = new Expression[argIndex - index]; | |
| 287 | + System.arraycopy(args, index, e, 0, argIndex - index); | |
| 288 | + argIndex = index; | |
| 289 | + return e; | |
| 290 | + } | |
| 291 | + protected final Statement statArgs(int index)[] { | |
| 292 | + Statement s[] = new Statement[argIndex - index]; | |
| 293 | + System.arraycopy(args, index, s, 0, argIndex - index); | |
| 294 | + argIndex = index; | |
| 295 | + return s; | |
| 296 | + } | |
| 297 | + | |
| 298 | + /** | |
| 299 | + * Expect a token, return its value, scan the next token or | |
| 300 | + * throw an exception. | |
| 301 | + */ | |
| 302 | + protected void expect(int t) throws SyntaxError, IOException { | |
| 303 | + if (token != t) { | |
| 304 | + switch (t) { | |
| 305 | + case IDENT: | |
| 306 | + env.error(scanner.prevPos, "identifier.expected"); | |
| 307 | + break; | |
| 308 | + default: | |
| 309 | + env.error(scanner.prevPos, "token.expected", opNames[t]); | |
| 310 | + break; | |
| 311 | + } | |
| 312 | + throw new SyntaxError(); | |
| 313 | + } | |
| 314 | + scan(); | |
| 315 | + } | |
| 316 | + | |
| 317 | + /** | |
| 318 | + * Parse a type expression. Does not parse the []'s. | |
| 319 | + */ | |
| 320 | + protected Expression parseTypeExpression() throws SyntaxError, IOException { | |
| 321 | + switch (token) { | |
| 322 | + case VOID: | |
| 323 | + return new TypeExpression(scan(), Type.tVoid); | |
| 324 | + case BOOLEAN: | |
| 325 | + return new TypeExpression(scan(), Type.tBoolean); | |
| 326 | + case BYTE: | |
| 327 | + return new TypeExpression(scan(), Type.tByte); | |
| 328 | + case CHAR: | |
| 329 | + return new TypeExpression(scan(), Type.tChar); | |
| 330 | + case SHORT: | |
| 331 | + return new TypeExpression(scan(), Type.tShort); | |
| 332 | + case INT: | |
| 333 | + return new TypeExpression(scan(), Type.tInt); | |
| 334 | + case LONG: | |
| 335 | + return new TypeExpression(scan(), Type.tLong); | |
| 336 | + case FLOAT: | |
| 337 | + return new TypeExpression(scan(), Type.tFloat); | |
| 338 | + case DOUBLE: | |
| 339 | + return new TypeExpression(scan(), Type.tDouble); | |
| 340 | + case IDENT: | |
| 341 | + Expression e = new IdentifierExpression(pos, scanner.idValue); | |
| 342 | + scan(); | |
| 343 | + while (token == FIELD) { | |
| 344 | + e = new FieldExpression(scan(), e, scanner.idValue); | |
| 345 | + expect(IDENT); | |
| 346 | + } | |
| 347 | + return e; | |
| 348 | + } | |
| 349 | + | |
| 350 | + env.error(pos, "type.expected"); | |
| 351 | + throw new SyntaxError(); | |
| 352 | + } | |
| 353 | + | |
| 354 | + /** | |
| 355 | + * Parse a method invocation. Should be called when the current | |
| 356 | + * then is the '(' of the argument list. | |
| 357 | + */ | |
| 358 | + protected Expression parseMethodExpression(Expression e, Identifier id) throws SyntaxError, IOException { | |
| 359 | + long p = scan(); | |
| 360 | + int i = argIndex; | |
| 361 | + if (token != RPAREN) { | |
| 362 | + addArgument(parseExpression()); | |
| 363 | + while (token == COMMA) { | |
| 364 | + scan(); | |
| 365 | + addArgument(parseExpression()); | |
| 366 | + } | |
| 367 | + } | |
| 368 | + expect(RPAREN); | |
| 369 | + return new MethodExpression(p, e, id, exprArgs(i)); | |
| 370 | + } | |
| 371 | + | |
| 372 | + /** | |
| 373 | + * Parse a new instance expression. Should be called when the current | |
| 374 | + * token is the '(' of the argument list. | |
| 375 | + */ | |
| 376 | + protected Expression parseNewInstanceExpression(long p, Expression outerArg, Expression type) throws SyntaxError, IOException { | |
| 377 | + int i = argIndex; | |
| 378 | + expect(LPAREN); | |
| 379 | + if (token != RPAREN) { | |
| 380 | + addArgument(parseExpression()); | |
| 381 | + while (token == COMMA) { | |
| 382 | + scan(); | |
| 383 | + addArgument(parseExpression()); | |
| 384 | + } | |
| 385 | + } | |
| 386 | + expect(RPAREN); | |
| 387 | + ClassDefinition body = null; | |
| 388 | + if (token == LBRACE && !(type instanceof TypeExpression)) { | |
| 389 | + long tp = pos; | |
| 390 | + // x = new Type(arg) { subclass body ... } | |
| 391 | + Identifier superName = FieldExpression.toIdentifier(type); | |
| 392 | + if (superName == null) { | |
| 393 | + env.error(type.getWhere(), "type.expected"); | |
| 394 | + } | |
| 395 | + Vector ext = new Vector(1); | |
| 396 | + Vector impl = new Vector(0); | |
| 397 | + ext.addElement(new IdentifierToken(idNull)); | |
| 398 | + if (token == IMPLEMENTS || token == EXTENDS) { | |
| 399 | + env.error(pos, "anonymous.extends"); | |
| 400 | + parseInheritance(ext, impl); // error recovery | |
| 401 | + } | |
| 402 | + body = parseClassBody(new IdentifierToken(tp, idNull), | |
| 403 | + M_ANONYMOUS | M_LOCAL, EXPR, null, | |
| 404 | + ext, impl, type.getWhere()); | |
| 405 | + } | |
| 406 | + if (outerArg == null && body == null) { | |
| 407 | + return new NewInstanceExpression(p, type, exprArgs(i)); | |
| 408 | + } | |
| 409 | + return new NewInstanceExpression(p, type, exprArgs(i), outerArg, body); | |
| 410 | + } | |
| 411 | + | |
| 412 | + /** | |
| 413 | + * Parse a primary expression. | |
| 414 | + */ | |
| 415 | + protected Expression parseTerm() throws SyntaxError, IOException { | |
| 416 | + switch (token) { | |
| 417 | + case CHARVAL: { | |
| 418 | + char v = scanner.charValue; | |
| 419 | + return new CharExpression(scan(), v); | |
| 420 | + } | |
| 421 | + case INTVAL: { | |
| 422 | + int v = scanner.intValue; | |
| 423 | + long q = scan(); | |
| 424 | + if (v < 0 && radix == 10) env.error(q, "overflow.int.dec"); | |
| 425 | + return new IntExpression(q, v); | |
| 426 | + } | |
| 427 | + case LONGVAL: { | |
| 428 | + long v = scanner.longValue; | |
| 429 | + long q = scan(); | |
| 430 | + if (v < 0 && radix == 10) env.error(q, "overflow.long.dec"); | |
| 431 | + return new LongExpression(q, v); | |
| 432 | + } | |
| 433 | + case FLOATVAL: { | |
| 434 | + float v = scanner.floatValue; | |
| 435 | + return new FloatExpression(scan(), v); | |
| 436 | + } | |
| 437 | + case DOUBLEVAL: { | |
| 438 | + double v = scanner.doubleValue; | |
| 439 | + return new DoubleExpression(scan(), v); | |
| 440 | + } | |
| 441 | + case STRINGVAL: { | |
| 442 | + String v = scanner.stringValue; | |
| 443 | + return new StringExpression(scan(), v); | |
| 444 | + } | |
| 445 | + case IDENT: { | |
| 446 | + Identifier v = scanner.idValue; | |
| 447 | + long p = scan(); | |
| 448 | + return (token == LPAREN) ? | |
| 449 | + parseMethodExpression(null, v) : new IdentifierExpression(p, v); | |
| 450 | + } | |
| 451 | + | |
| 452 | + case TRUE: | |
| 453 | + return new BooleanExpression(scan(), true); | |
| 454 | + case FALSE: | |
| 455 | + return new BooleanExpression(scan(), false); | |
| 456 | + case NULL: | |
| 457 | + return new NullExpression(scan()); | |
| 458 | + | |
| 459 | + case THIS: { | |
| 460 | + Expression e = new ThisExpression(scan()); | |
| 461 | + return (token == LPAREN) ? parseMethodExpression(e, idInit) : e; | |
| 462 | + } | |
| 463 | + case SUPER: { | |
| 464 | + Expression e = new SuperExpression(scan()); | |
| 465 | + return (token == LPAREN) ? parseMethodExpression(e, idInit) : e; | |
| 466 | + } | |
| 467 | + | |
| 468 | + case VOID: | |
| 469 | + case BOOLEAN: | |
| 470 | + case BYTE: | |
| 471 | + case CHAR: | |
| 472 | + case SHORT: | |
| 473 | + case INT: | |
| 474 | + case LONG: | |
| 475 | + case FLOAT: | |
| 476 | + case DOUBLE: | |
| 477 | + return parseTypeExpression(); | |
| 478 | + | |
| 479 | + case ADD: { | |
| 480 | + long p = scan(); | |
| 481 | + switch (token) { | |
| 482 | + case INTVAL: { | |
| 483 | + int v = scanner.intValue; | |
| 484 | + long q = scan(); | |
| 485 | + if (v < 0 && radix == 10) env.error(q, "overflow.int.dec"); | |
| 486 | + return new IntExpression(q, v); | |
| 487 | + } | |
| 488 | + case LONGVAL: { | |
| 489 | + long v = scanner.longValue; | |
| 490 | + long q = scan(); | |
| 491 | + if (v < 0 && radix == 10) env.error(q, "overflow.long.dec"); | |
| 492 | + return new LongExpression(q, v); | |
| 493 | + } | |
| 494 | + case FLOATVAL: { | |
| 495 | + float v = scanner.floatValue; | |
| 496 | + return new FloatExpression(scan(), v); | |
| 497 | + } | |
| 498 | + case DOUBLEVAL: { | |
| 499 | + double v = scanner.doubleValue; | |
| 500 | + return new DoubleExpression(scan(), v); | |
| 501 | + } | |
| 502 | + } | |
| 503 | + return new PositiveExpression(p, parseTerm()); | |
| 504 | + } | |
| 505 | + case SUB: { | |
| 506 | + long p = scan(); | |
| 507 | + switch (token) { | |
| 508 | + case INTVAL: { | |
| 509 | + int v = -scanner.intValue; | |
| 510 | + return new IntExpression(scan(), v); | |
| 511 | + } | |
| 512 | + case LONGVAL: { | |
| 513 | + long v = -scanner.longValue; | |
| 514 | + return new LongExpression(scan(), v); | |
| 515 | + } | |
| 516 | + case FLOATVAL: { | |
| 517 | + float v = -scanner.floatValue; | |
| 518 | + return new FloatExpression(scan(), v); | |
| 519 | + } | |
| 520 | + case DOUBLEVAL: { | |
| 521 | + double v = -scanner.doubleValue; | |
| 522 | + return new DoubleExpression(scan(), v); | |
| 523 | + } | |
| 524 | + } | |
| 525 | + return new NegativeExpression(p, parseTerm()); | |
| 526 | + } | |
| 527 | + case NOT: | |
| 528 | + return new NotExpression(scan(), parseTerm()); | |
| 529 | + case BITNOT: | |
| 530 | + return new BitNotExpression(scan(), parseTerm()); | |
| 531 | + case INC: | |
| 532 | + return new PreIncExpression(scan(), parseTerm()); | |
| 533 | + case DEC: | |
| 534 | + return new PreDecExpression(scan(), parseTerm()); | |
| 535 | + | |
| 536 | + case LPAREN: { | |
| 537 | + // bracketed-expr: (expr) | |
| 538 | + long p = scan(); | |
| 539 | + Expression e = parseExpression(); | |
| 540 | + expect(RPAREN); | |
| 541 | + | |
| 542 | + if (e.getOp() == TYPE) { | |
| 543 | + // cast-expr: (simple-type) expr | |
| 544 | + return new CastExpression(p, e, parseTerm()); | |
| 545 | + } | |
| 546 | + | |
| 547 | + switch (token) { | |
| 548 | + | |
| 549 | + // We handle INC and DEC specially. | |
| 550 | + // See the discussion in JLS section 15.14.1. | |
| 551 | + // (Part of fix for 4044502.) | |
| 552 | + | |
| 553 | + case INC: | |
| 554 | + // We know this must be a postfix increment. | |
| 555 | + return new PostIncExpression(scan(), e); | |
| 556 | + | |
| 557 | + case DEC: | |
| 558 | + // We know this must be a postfix decrement. | |
| 559 | + return new PostDecExpression(scan(), e); | |
| 560 | + | |
| 561 | + case LPAREN: | |
| 562 | + case CHARVAL: | |
| 563 | + case INTVAL: | |
| 564 | + case LONGVAL: | |
| 565 | + case FLOATVAL: | |
| 566 | + case DOUBLEVAL: | |
| 567 | + case STRINGVAL: | |
| 568 | + case IDENT: | |
| 569 | + case TRUE: | |
| 570 | + case FALSE: | |
| 571 | + case NOT: | |
| 572 | + case BITNOT: | |
| 573 | + case THIS: | |
| 574 | + case SUPER: | |
| 575 | + case NULL: | |
| 576 | + case NEW: | |
| 577 | + // cast-expr: (expr) expr | |
| 578 | + return new CastExpression(p, e, parseTerm()); | |
| 579 | + } | |
| 580 | + return new ExprExpression(p, e); | |
| 581 | + } | |
| 582 | + | |
| 583 | + case LBRACE: { | |
| 584 | + // array initializer: {expr1, expr2, ... exprn} | |
| 585 | + long p = scan(); | |
| 586 | + int i = argIndex; | |
| 587 | + if (token != RBRACE) { | |
| 588 | + addArgument(parseExpression()); | |
| 589 | + while (token == COMMA) { | |
| 590 | + scan(); | |
| 591 | + if (token == RBRACE) { | |
| 592 | + break; | |
| 593 | + } | |
| 594 | + addArgument(parseExpression()); | |
| 595 | + } | |
| 596 | + } | |
| 597 | + expect(RBRACE); | |
| 598 | + return new ArrayExpression(p, exprArgs(i)); | |
| 599 | + } | |
| 600 | + | |
| 601 | + case NEW: { | |
| 602 | + long p = scan(); | |
| 603 | + int i = argIndex; | |
| 604 | + | |
| 605 | + if (token == LPAREN) { | |
| 606 | + scan(); | |
| 607 | + Expression e = parseExpression(); | |
| 608 | + expect(RPAREN); | |
| 609 | + env.error(p, "not.supported", "new(...)"); | |
| 610 | + return new NullExpression(p); | |
| 611 | + } | |
| 612 | + | |
| 613 | + Expression e = parseTypeExpression(); | |
| 614 | + | |
| 615 | + if (token == LSQBRACKET) { | |
| 616 | + while (token == LSQBRACKET) { | |
| 617 | + scan(); | |
| 618 | + addArgument((token != RSQBRACKET) ? parseExpression() : null); | |
| 619 | + expect(RSQBRACKET); | |
| 620 | + } | |
| 621 | + Expression[] dims = exprArgs(i); | |
| 622 | + if (token == LBRACE) { | |
| 623 | + return new NewArrayExpression(p, e, dims, parseTerm()); | |
| 624 | + } | |
| 625 | + return new NewArrayExpression(p, e, dims); | |
| 626 | + } else { | |
| 627 | + return parseNewInstanceExpression(p, null, e); | |
| 628 | + } | |
| 629 | + } | |
| 630 | + } | |
| 631 | + | |
| 632 | + // System.err.println("NEAR: " + opNames[token]); | |
| 633 | + env.error(scanner.prevPos, "missing.term"); | |
| 634 | + return new IntExpression(pos, 0); | |
| 635 | + } | |
| 636 | + | |
| 637 | + /** | |
| 638 | + * Parse an expression. | |
| 639 | + */ | |
| 640 | + protected Expression parseExpression() throws SyntaxError, IOException { | |
| 641 | + for (Expression e = parseTerm() ; e != null ; e = e.order()) { | |
| 642 | + Expression more = parseBinaryExpression(e); | |
| 643 | + if (more == null) | |
| 644 | + return e; | |
| 645 | + e = more; | |
| 646 | + } | |
| 647 | + // this return is bogus | |
| 648 | + return null; | |
| 649 | + } | |
| 650 | + | |
| 651 | + /** | |
| 652 | + * Given a left-hand term, parse an operator and right-hand term. | |
| 653 | + */ | |
| 654 | + protected Expression parseBinaryExpression(Expression e) throws SyntaxError, IOException { | |
| 655 | + if (e != null) { | |
| 656 | + switch (token) { | |
| 657 | + case LSQBRACKET: { | |
| 658 | + // index: expr1[expr2] | |
| 659 | + long p = scan(); | |
| 660 | + Expression index = (token != RSQBRACKET) ? parseExpression() : null; | |
| 661 | + expect(RSQBRACKET); | |
| 662 | + e = new ArrayAccessExpression(p, e, index); | |
| 663 | + break; | |
| 664 | + } | |
| 665 | + | |
| 666 | + case INC: | |
| 667 | + e = new PostIncExpression(scan(), e); | |
| 668 | + break; | |
| 669 | + case DEC: | |
| 670 | + e = new PostDecExpression(scan(), e); | |
| 671 | + break; | |
| 672 | + case FIELD: { | |
| 673 | + long p = scan(); | |
| 674 | + if (token == THIS) { | |
| 675 | + // class C { class N { ... C.this ... } } | |
| 676 | + // class C { class N { N(C c){ ... c.this() ... } } } | |
| 677 | + long q = scan(); | |
| 678 | + if (token == LPAREN) { | |
| 679 | + e = new ThisExpression(q, e); | |
| 680 | + e = parseMethodExpression(e, idInit); | |
| 681 | + } else { | |
| 682 | + e = new FieldExpression(p, e, idThis); | |
| 683 | + } | |
| 684 | + break; | |
| 685 | + } | |
| 686 | + if (token == SUPER) { | |
| 687 | + // class D extends C.N { D(C.N n) { n.super(); } } | |
| 688 | + // Also, 'C.super', as in: | |
| 689 | + // class C extends CS { class N { ... C.super.foo ... } } | |
| 690 | + // class C extends CS { class N { ... C.super.foo() ... } } | |
| 691 | + long q = scan(); | |
| 692 | + if (token == LPAREN) { | |
| 693 | + e = new SuperExpression(q, e); | |
| 694 | + e = parseMethodExpression(e, idInit); | |
| 695 | + } else { | |
| 696 | + // We must check elsewhere that this expression | |
| 697 | + // does not stand alone, but qualifies a member name. | |
| 698 | + e = new FieldExpression(p, e, idSuper); | |
| 699 | + } | |
| 700 | + break; | |
| 701 | + } | |
| 702 | + if (token == NEW) { | |
| 703 | + // new C().new N() | |
| 704 | + scan(); | |
| 705 | + if (token != IDENT) | |
| 706 | + expect(IDENT); | |
| 707 | + e = parseNewInstanceExpression(p, e, parseTypeExpression()); | |
| 708 | + break; | |
| 709 | + } | |
| 710 | + if (token == CLASS) { | |
| 711 | + // just class literals, really | |
| 712 | + // Class c = C.class; | |
| 713 | + scan(); | |
| 714 | + e = new FieldExpression(p, e, idClass); | |
| 715 | + break; | |
| 716 | + } | |
| 717 | + Identifier id = scanner.idValue; | |
| 718 | + expect(IDENT); | |
| 719 | + if (token == LPAREN) { | |
| 720 | + e = parseMethodExpression(e, id); | |
| 721 | + } else { | |
| 722 | + e = new FieldExpression(p, e, id); | |
| 723 | + } | |
| 724 | + break; | |
| 725 | + } | |
| 726 | + case INSTANCEOF: | |
| 727 | + e = new InstanceOfExpression(scan(), e, parseTerm()); | |
| 728 | + break; | |
| 729 | + case ADD: | |
| 730 | + e = new AddExpression(scan(), e, parseTerm()); | |
| 731 | + break; | |
| 732 | + case SUB: | |
| 733 | + e = new SubtractExpression(scan(), e, parseTerm()); | |
| 734 | + break; | |
| 735 | + case MUL: | |
| 736 | + e = new MultiplyExpression(scan(), e, parseTerm()); | |
| 737 | + break; | |
| 738 | + case DIV: | |
| 739 | + e = new DivideExpression(scan(), e, parseTerm()); | |
| 740 | + break; | |
| 741 | + case REM: | |
| 742 | + e = new RemainderExpression(scan(), e, parseTerm()); | |
| 743 | + break; | |
| 744 | + case LSHIFT: | |
| 745 | + e = new ShiftLeftExpression(scan(), e, parseTerm()); | |
| 746 | + break; | |
| 747 | + case RSHIFT: | |
| 748 | + e = new ShiftRightExpression(scan(), e, parseTerm()); | |
| 749 | + break; | |
| 750 | + case URSHIFT: | |
| 751 | + e = new UnsignedShiftRightExpression(scan(), e, parseTerm()); | |
| 752 | + break; | |
| 753 | + case LT: | |
| 754 | + e = new LessExpression(scan(), e, parseTerm()); | |
| 755 | + break; | |
| 756 | + case LE: | |
| 757 | + e = new LessOrEqualExpression(scan(), e, parseTerm()); | |
| 758 | + break; | |
| 759 | + case GT: | |
| 760 | + e = new GreaterExpression(scan(), e, parseTerm()); | |
| 761 | + break; | |
| 762 | + case GE: | |
| 763 | + e = new GreaterOrEqualExpression(scan(), e, parseTerm()); | |
| 764 | + break; | |
| 765 | + case EQ: | |
| 766 | + e = new EqualExpression(scan(), e, parseTerm()); | |
| 767 | + break; | |
| 768 | + case NE: | |
| 769 | + e = new NotEqualExpression(scan(), e, parseTerm()); | |
| 770 | + break; | |
| 771 | + case BITAND: | |
| 772 | + e = new BitAndExpression(scan(), e, parseTerm()); | |
| 773 | + break; | |
| 774 | + case BITXOR: | |
| 775 | + e = new BitXorExpression(scan(), e, parseTerm()); | |
| 776 | + break; | |
| 777 | + case BITOR: | |
| 778 | + e = new BitOrExpression(scan(), e, parseTerm()); | |
| 779 | + break; | |
| 780 | + case AND: | |
| 781 | + e = new AndExpression(scan(), e, parseTerm()); | |
| 782 | + break; | |
| 783 | + case OR: | |
| 784 | + e = new OrExpression(scan(), e, parseTerm()); | |
| 785 | + break; | |
| 786 | + case ASSIGN: | |
| 787 | + e = new AssignExpression(scan(), e, parseTerm()); | |
| 788 | + break; | |
| 789 | + case ASGMUL: | |
| 790 | + e = new AssignMultiplyExpression(scan(), e, parseTerm()); | |
| 791 | + break; | |
| 792 | + case ASGDIV: | |
| 793 | + e = new AssignDivideExpression(scan(), e, parseTerm()); | |
| 794 | + break; | |
| 795 | + case ASGREM: | |
| 796 | + e = new AssignRemainderExpression(scan(), e, parseTerm()); | |
| 797 | + break; | |
| 798 | + case ASGADD: | |
| 799 | + e = new AssignAddExpression(scan(), e, parseTerm()); | |
| 800 | + break; | |
| 801 | + case ASGSUB: | |
| 802 | + e = new AssignSubtractExpression(scan(), e, parseTerm()); | |
| 803 | + break; | |
| 804 | + case ASGLSHIFT: | |
| 805 | + e = new AssignShiftLeftExpression(scan(), e, parseTerm()); | |
| 806 | + break; | |
| 807 | + case ASGRSHIFT: | |
| 808 | + e = new AssignShiftRightExpression(scan(), e, parseTerm()); | |
| 809 | + break; | |
| 810 | + case ASGURSHIFT: | |
| 811 | + e = new AssignUnsignedShiftRightExpression(scan(), e, parseTerm()); | |
| 812 | + break; | |
| 813 | + case ASGBITAND: | |
| 814 | + e = new AssignBitAndExpression(scan(), e, parseTerm()); | |
| 815 | + break; | |
| 816 | + case ASGBITOR: | |
| 817 | + e = new AssignBitOrExpression(scan(), e, parseTerm()); | |
| 818 | + break; | |
| 819 | + case ASGBITXOR: | |
| 820 | + e = new AssignBitXorExpression(scan(), e, parseTerm()); | |
| 821 | + break; | |
| 822 | + case QUESTIONMARK: { | |
| 823 | + long p = scan(); | |
| 824 | + Expression second = parseExpression(); | |
| 825 | + expect(COLON); | |
| 826 | + Expression third = parseExpression(); | |
| 827 | + | |
| 828 | + // The grammar in the JLS does not allow assignment | |
| 829 | + // expressions as the third part of a ?: expression. | |
| 830 | + // Even though javac has no trouble parsing this, | |
| 831 | + // check for this case and signal an error. | |
| 832 | + // (fix for bug 4092958) | |
| 833 | + if (third instanceof AssignExpression | |
| 834 | + || third instanceof AssignOpExpression) { | |
| 835 | + env.error(third.getWhere(), "assign.in.conditionalexpr"); | |
| 836 | + } | |
| 837 | + | |
| 838 | + e = new ConditionalExpression(p, e, second, third); | |
| 839 | + break; | |
| 840 | + } | |
| 841 | + | |
| 842 | + default: | |
| 843 | + return null; // mark end of binary expressions | |
| 844 | + } | |
| 845 | + } | |
| 846 | + return e; // return more binary expression stuff | |
| 847 | + } | |
| 848 | + | |
| 849 | + /** | |
| 850 | + * Recover after a syntax error in a statement. This involves | |
| 851 | + * discarding tokens until EOF or a possible continuation is | |
| 852 | + * encountered. | |
| 853 | + */ | |
| 854 | + protected boolean recoverStatement() throws SyntaxError, IOException { | |
| 855 | + while (true) { | |
| 856 | + switch (token) { | |
| 857 | + case EOF: | |
| 858 | + case RBRACE: | |
| 859 | + case LBRACE: | |
| 860 | + case IF: | |
| 861 | + case FOR: | |
| 862 | + case WHILE: | |
| 863 | + case DO: | |
| 864 | + case TRY: | |
| 865 | + case CATCH: | |
| 866 | + case FINALLY: | |
| 867 | + case BREAK: | |
| 868 | + case CONTINUE: | |
| 869 | + case RETURN: | |
| 870 | + // begin of a statement, return | |
| 871 | + return true; | |
| 872 | + | |
| 873 | + case VOID: | |
| 874 | + case STATIC: | |
| 875 | + case PUBLIC: | |
| 876 | + case PRIVATE: | |
| 877 | + case SYNCHRONIZED: | |
| 878 | + case INTERFACE: | |
| 879 | + case CLASS: | |
| 880 | + case TRANSIENT: | |
| 881 | + // begin of something outside a statement, panic some more | |
| 882 | + expect(RBRACE); | |
| 883 | + return false; | |
| 884 | + | |
| 885 | + case LPAREN: | |
| 886 | + match(LPAREN, RPAREN); | |
| 887 | + scan(); | |
| 888 | + break; | |
| 889 | + | |
| 890 | + case LSQBRACKET: | |
| 891 | + match(LSQBRACKET, RSQBRACKET); | |
| 892 | + scan(); | |
| 893 | + break; | |
| 894 | + | |
| 895 | + default: | |
| 896 | + // don't know what to do, skip | |
| 897 | + scan(); | |
| 898 | + break; | |
| 899 | + } | |
| 900 | + } | |
| 901 | + } | |
| 902 | + | |
| 903 | + /** | |
| 904 | + * Parse declaration, called after the type expression | |
| 905 | + * has been parsed and the current token is IDENT. | |
| 906 | + */ | |
| 907 | + protected Statement parseDeclaration(long p, int mod, Expression type) throws SyntaxError, IOException { | |
| 908 | + int i = argIndex; | |
| 909 | + if (token == IDENT) { | |
| 910 | + addArgument(new VarDeclarationStatement(pos, parseExpression())); | |
| 911 | + while (token == COMMA) { | |
| 912 | + scan(); | |
| 913 | + addArgument(new VarDeclarationStatement(pos, parseExpression())); | |
| 914 | + } | |
| 915 | + } | |
| 916 | + return new DeclarationStatement(p, mod, type, statArgs(i)); | |
| 917 | + } | |
| 918 | + | |
| 919 | + /** | |
| 920 | + * Check if an expression is a legal toplevel expression. | |
| 921 | + * Only method, inc, dec, and new expression are allowed. | |
| 922 | + */ | |
| 923 | + protected void topLevelExpression(Expression e) { | |
| 924 | + switch (e.getOp()) { | |
| 925 | + case ASSIGN: | |
| 926 | + case ASGMUL: | |
| 927 | + case ASGDIV: | |
| 928 | + case ASGREM: | |
| 929 | + case ASGADD: | |
| 930 | + case ASGSUB: | |
| 931 | + case ASGLSHIFT: | |
| 932 | + case ASGRSHIFT: | |
| 933 | + case ASGURSHIFT: | |
| 934 | + case ASGBITAND: | |
| 935 | + case ASGBITOR: | |
| 936 | + case ASGBITXOR: | |
| 937 | + case PREINC: | |
| 938 | + case PREDEC: | |
| 939 | + case POSTINC: | |
| 940 | + case POSTDEC: | |
| 941 | + case METHOD: | |
| 942 | + case NEWINSTANCE: | |
| 943 | + return; | |
| 944 | + } | |
| 945 | + env.error(e.getWhere(), "invalid.expr"); | |
| 946 | + } | |
| 947 | + | |
| 948 | + /** | |
| 949 | + * Parse a statement. | |
| 950 | + */ | |
| 951 | + protected Statement parseStatement() throws SyntaxError, IOException { | |
| 952 | + switch (token) { | |
| 953 | + case SEMICOLON: | |
| 954 | + return new CompoundStatement(scan(), new Statement[0]); | |
| 955 | + | |
| 956 | + case LBRACE: | |
| 957 | + return parseBlockStatement(); | |
| 958 | + | |
| 959 | + case IF: { | |
| 960 | + // if-statement: if (expr) stat | |
| 961 | + // if-statement: if (expr) stat else stat | |
| 962 | + long p = scan(); | |
| 963 | + | |
| 964 | + expect(LPAREN); | |
| 965 | + Expression c = parseExpression(); | |
| 966 | + expect(RPAREN); | |
| 967 | + Statement t = parseStatement(); | |
| 968 | + if (token == ELSE) { | |
| 969 | + scan(); | |
| 970 | + return new IfStatement(p, c, t, parseStatement()); | |
| 971 | + } else { | |
| 972 | + return new IfStatement(p, c, t, null); | |
| 973 | + } | |
| 974 | + } | |
| 975 | + | |
| 976 | + case ELSE: { | |
| 977 | + // else-statement: else stat | |
| 978 | + env.error(scan(), "else.without.if"); | |
| 979 | + return parseStatement(); | |
| 980 | + } | |
| 981 | + | |
| 982 | + case FOR: { | |
| 983 | + // for-statement: for (decl-expr? ; expr? ; expr?) stat | |
| 984 | + long p = scan(); | |
| 985 | + Statement init = null; | |
| 986 | + Expression cond = null, inc = null; | |
| 987 | + | |
| 988 | + expect(LPAREN); | |
| 989 | + if (token != SEMICOLON) { | |
| 990 | + long p2 = pos; | |
| 991 | + int mod = parseModifiers(M_FINAL); | |
| 992 | + Expression e = parseExpression(); | |
| 993 | + | |
| 994 | + if (token == IDENT) { | |
| 995 | + init = parseDeclaration(p2, mod, e); | |
| 996 | + } else { | |
| 997 | + if (mod != 0) { | |
| 998 | + expect(IDENT); // should have been a declaration | |
| 999 | + } | |
| 1000 | + topLevelExpression(e); | |
| 1001 | + while (token == COMMA) { | |
| 1002 | + long p3 = scan(); | |
| 1003 | + Expression e2 = parseExpression(); | |
| 1004 | + topLevelExpression(e2); | |
| 1005 | + e = new CommaExpression(p3, e, e2); | |
| 1006 | + } | |
| 1007 | + init = new ExpressionStatement(p2, e); | |
| 1008 | + } | |
| 1009 | + } | |
| 1010 | + expect(SEMICOLON); | |
| 1011 | + if (token != SEMICOLON) { | |
| 1012 | + cond = parseExpression(); | |
| 1013 | + } | |
| 1014 | + expect(SEMICOLON); | |
| 1015 | + if (token != RPAREN) { | |
| 1016 | + inc = parseExpression(); | |
| 1017 | + topLevelExpression(inc); | |
| 1018 | + while (token == COMMA) { | |
| 1019 | + long p2 = scan(); | |
| 1020 | + Expression e2 = parseExpression(); | |
| 1021 | + topLevelExpression(e2); | |
| 1022 | + inc = new CommaExpression(p2, inc, e2); | |
| 1023 | + } | |
| 1024 | + } | |
| 1025 | + expect(RPAREN); | |
| 1026 | + return new ForStatement(p, init, cond, inc, parseStatement()); | |
| 1027 | + } | |
| 1028 | + | |
| 1029 | + case WHILE: { | |
| 1030 | + // while-statement: while (expr) stat | |
| 1031 | + long p = scan(); | |
| 1032 | + | |
| 1033 | + expect(LPAREN); | |
| 1034 | + Expression cond = parseExpression(); | |
| 1035 | + expect(RPAREN); | |
| 1036 | + return new WhileStatement(p, cond, parseStatement()); | |
| 1037 | + } | |
| 1038 | + | |
| 1039 | + case DO: { | |
| 1040 | + // do-statement: do stat while (expr) | |
| 1041 | + long p = scan(); | |
| 1042 | + | |
| 1043 | + Statement body = parseStatement(); | |
| 1044 | + expect(WHILE); | |
| 1045 | + expect(LPAREN); | |
| 1046 | + Expression cond = parseExpression(); | |
| 1047 | + expect(RPAREN); | |
| 1048 | + expect(SEMICOLON); | |
| 1049 | + return new DoStatement(p, body, cond); | |
| 1050 | + } | |
| 1051 | + | |
| 1052 | + case BREAK: { | |
| 1053 | + // break-statement: break ; | |
| 1054 | + long p = scan(); | |
| 1055 | + Identifier label = null; | |
| 1056 | + | |
| 1057 | + if (token == IDENT) { | |
| 1058 | + label = scanner.idValue; | |
| 1059 | + scan(); | |
| 1060 | + } | |
| 1061 | + expect(SEMICOLON); | |
| 1062 | + return new BreakStatement(p, label); | |
| 1063 | + } | |
| 1064 | + | |
| 1065 | + case CONTINUE: { | |
| 1066 | + // continue-statement: continue ; | |
| 1067 | + long p = scan(); | |
| 1068 | + Identifier label = null; | |
| 1069 | + | |
| 1070 | + if (token == IDENT) { | |
| 1071 | + label = scanner.idValue; | |
| 1072 | + scan(); | |
| 1073 | + } | |
| 1074 | + expect(SEMICOLON); | |
| 1075 | + return new ContinueStatement(p, label); | |
| 1076 | + } | |
| 1077 | + | |
| 1078 | + case RETURN: { | |
| 1079 | + // return-statement: return ; | |
| 1080 | + // return-statement: return expr ; | |
| 1081 | + long p = scan(); | |
| 1082 | + Expression e = null; | |
| 1083 | + | |
| 1084 | + if (token != SEMICOLON) { | |
| 1085 | + e = parseExpression(); | |
| 1086 | + } | |
| 1087 | + expect(SEMICOLON); | |
| 1088 | + return new ReturnStatement(p, e); | |
| 1089 | + } | |
| 1090 | + | |
| 1091 | + case SWITCH: { | |
| 1092 | + // switch statement: switch ( expr ) stat | |
| 1093 | + long p = scan(); | |
| 1094 | + int i = argIndex; | |
| 1095 | + | |
| 1096 | + expect(LPAREN); | |
| 1097 | + Expression e = parseExpression(); | |
| 1098 | + expect(RPAREN); | |
| 1099 | + expect(LBRACE); | |
| 1100 | + | |
| 1101 | + while ((token != EOF) && (token != RBRACE)) { | |
| 1102 | + int j = argIndex; | |
| 1103 | + try { | |
| 1104 | + switch (token) { | |
| 1105 | + case CASE: | |
| 1106 | + // case-statement: case expr: | |
| 1107 | + addArgument(new CaseStatement(scan(), parseExpression())); | |
| 1108 | + expect(COLON); | |
| 1109 | + break; | |
| 1110 | + | |
| 1111 | + case DEFAULT: | |
| 1112 | + // default-statement: default: | |
| 1113 | + addArgument(new CaseStatement(scan(), null)); | |
| 1114 | + expect(COLON); | |
| 1115 | + break; | |
| 1116 | + | |
| 1117 | + default: | |
| 1118 | + addArgument(parseStatement()); | |
| 1119 | + break; | |
| 1120 | + } | |
| 1121 | + } catch (SyntaxError ee) { | |
| 1122 | + argIndex = j; | |
| 1123 | + if (!recoverStatement()) { | |
| 1124 | + throw ee; | |
| 1125 | + } | |
| 1126 | + } | |
| 1127 | + } | |
| 1128 | + expect(RBRACE); | |
| 1129 | + return new SwitchStatement(p, e, statArgs(i)); | |
| 1130 | + } | |
| 1131 | + | |
| 1132 | + case CASE: { | |
| 1133 | + // case-statement: case expr : stat | |
| 1134 | + env.error(pos, "case.without.switch"); | |
| 1135 | + while (token == CASE) { | |
| 1136 | + scan(); | |
| 1137 | + parseExpression(); | |
| 1138 | + expect(COLON); | |
| 1139 | + } | |
| 1140 | + return parseStatement(); | |
| 1141 | + } | |
| 1142 | + | |
| 1143 | + case DEFAULT: { | |
| 1144 | + // default-statement: default : stat | |
| 1145 | + env.error(pos, "default.without.switch"); | |
| 1146 | + scan(); | |
| 1147 | + expect(COLON); | |
| 1148 | + return parseStatement(); | |
| 1149 | + } | |
| 1150 | + | |
| 1151 | + case TRY: { | |
| 1152 | + // try-statement: try stat catch (type-expr ident) stat finally stat | |
| 1153 | + long p = scan(); | |
| 1154 | + Statement init = null; // try-object specification | |
| 1155 | + int i = argIndex; | |
| 1156 | + boolean catches = false; | |
| 1157 | + | |
| 1158 | + if (false && token == LPAREN) { | |
| 1159 | + expect(LPAREN); | |
| 1160 | + long p2 = pos; | |
| 1161 | + int mod = parseModifiers(M_FINAL); | |
| 1162 | + Expression e = parseExpression(); | |
| 1163 | + | |
| 1164 | + if (token == IDENT) { | |
| 1165 | + init = parseDeclaration(p2, mod, e); | |
| 1166 | + // leave check for try (T x, y) for semantic phase | |
| 1167 | + } else { | |
| 1168 | + if (mod != 0) { | |
| 1169 | + expect(IDENT); // should have been a declaration | |
| 1170 | + } | |
| 1171 | + init = new ExpressionStatement(p2, e); | |
| 1172 | + } | |
| 1173 | + expect(RPAREN); | |
| 1174 | + } | |
| 1175 | + | |
| 1176 | + Statement s = parseBlockStatement(); | |
| 1177 | + | |
| 1178 | + if (init != null) { | |
| 1179 | + // s = new FinallyStatement(p, init, s, 0); | |
| 1180 | + } | |
| 1181 | + | |
| 1182 | + while (token == CATCH) { | |
| 1183 | + long pp = pos; | |
| 1184 | + expect(CATCH); | |
| 1185 | + expect(LPAREN); | |
| 1186 | + int mod = parseModifiers(M_FINAL); | |
| 1187 | + Expression t = parseExpression(); | |
| 1188 | + IdentifierToken id = scanner.getIdToken(); | |
| 1189 | + expect(IDENT); | |
| 1190 | + id.modifiers = mod; | |
| 1191 | + // We only catch Throwable's, so this is no longer required | |
| 1192 | + // while (token == LSQBRACKET) { | |
| 1193 | + // t = new ArrayAccessExpression(scan(), t, null); | |
| 1194 | + // expect(RSQBRACKET); | |
| 1195 | + // } | |
| 1196 | + expect(RPAREN); | |
| 1197 | + addArgument(new CatchStatement(pp, t, id, parseBlockStatement())); | |
| 1198 | + catches = true; | |
| 1199 | + } | |
| 1200 | + | |
| 1201 | + if (catches) | |
| 1202 | + s = new TryStatement(p, s, statArgs(i)); | |
| 1203 | + | |
| 1204 | + if (token == FINALLY) { | |
| 1205 | + scan(); | |
| 1206 | + return new FinallyStatement(p, s, parseBlockStatement()); | |
| 1207 | + } else if (catches || init != null) { | |
| 1208 | + return s; | |
| 1209 | + } else { | |
| 1210 | + env.error(pos, "try.without.catch.finally"); | |
| 1211 | + return new TryStatement(p, s, null); | |
| 1212 | + } | |
| 1213 | + } | |
| 1214 | + | |
| 1215 | + case CATCH: { | |
| 1216 | + // catch-statement: catch (expr ident) stat finally stat | |
| 1217 | + env.error(pos, "catch.without.try"); | |
| 1218 | + | |
| 1219 | + Statement s; | |
| 1220 | + do { | |
| 1221 | + scan(); | |
| 1222 | + expect(LPAREN); | |
| 1223 | + parseModifiers(M_FINAL); | |
| 1224 | + parseExpression(); | |
| 1225 | + expect(IDENT); | |
| 1226 | + expect(RPAREN); | |
| 1227 | + s = parseBlockStatement(); | |
| 1228 | + } while (token == CATCH); | |
| 1229 | + | |
| 1230 | + if (token == FINALLY) { | |
| 1231 | + scan(); | |
| 1232 | + s = parseBlockStatement(); | |
| 1233 | + } | |
| 1234 | + return s; | |
| 1235 | + } | |
| 1236 | + | |
| 1237 | + case FINALLY: { | |
| 1238 | + // finally-statement: finally stat | |
| 1239 | + env.error(pos, "finally.without.try"); | |
| 1240 | + scan(); | |
| 1241 | + return parseBlockStatement(); | |
| 1242 | + } | |
| 1243 | + | |
| 1244 | + case THROW: { | |
| 1245 | + // throw-statement: throw expr; | |
| 1246 | + long p = scan(); | |
| 1247 | + Expression e = parseExpression(); | |
| 1248 | + expect(SEMICOLON); | |
| 1249 | + return new ThrowStatement(p, e); | |
| 1250 | + } | |
| 1251 | + | |
| 1252 | + case GOTO: { | |
| 1253 | + long p = scan(); | |
| 1254 | + expect(IDENT); | |
| 1255 | + expect(SEMICOLON); | |
| 1256 | + env.error(p, "not.supported", "goto"); | |
| 1257 | + return new CompoundStatement(p, new Statement[0]); | |
| 1258 | + } | |
| 1259 | + | |
| 1260 | + case SYNCHRONIZED: { | |
| 1261 | + // synchronized-statement: synchronized (expr) stat | |
| 1262 | + long p = scan(); | |
| 1263 | + expect(LPAREN); | |
| 1264 | + Expression e = parseExpression(); | |
| 1265 | + expect(RPAREN); | |
| 1266 | + return new SynchronizedStatement(p, e, parseBlockStatement()); | |
| 1267 | + } | |
| 1268 | + | |
| 1269 | + case INTERFACE: | |
| 1270 | + case CLASS: | |
| 1271 | + // Inner class. | |
| 1272 | + return parseLocalClass(0); | |
| 1273 | + | |
| 1274 | + case CONST: | |
| 1275 | + case ABSTRACT: | |
| 1276 | + case FINAL: | |
| 1277 | + case STRICTFP: { | |
| 1278 | + // a declaration of some sort | |
| 1279 | + long p = pos; | |
| 1280 | + | |
| 1281 | + // A class which is local to a block is not a member, and so | |
| 1282 | + // cannot be public, private, protected, or static. It is in | |
| 1283 | + // effect private to the block, since it cannot be used outside | |
| 1284 | + // its scope. | |
| 1285 | + // | |
| 1286 | + // However, any class (if it has a name) can be declared final, | |
| 1287 | + // abstract, or strictfp. | |
| 1288 | + int mod = parseModifiers(M_FINAL | M_ABSTRACT | |
| 1289 | + | M_STRICTFP ); | |
| 1290 | + | |
| 1291 | + switch (token) { | |
| 1292 | + case INTERFACE: | |
| 1293 | + case CLASS: | |
| 1294 | + return parseLocalClass(mod); | |
| 1295 | + | |
| 1296 | + case BOOLEAN: | |
| 1297 | + case BYTE: | |
| 1298 | + case CHAR: | |
| 1299 | + case SHORT: | |
| 1300 | + case INT: | |
| 1301 | + case LONG: | |
| 1302 | + case FLOAT: | |
| 1303 | + case DOUBLE: | |
| 1304 | + case IDENT: { | |
| 1305 | + if ((mod & (M_ABSTRACT | M_STRICTFP )) != 0) { | |
| 1306 | + mod &= ~ (M_ABSTRACT | M_STRICTFP ); | |
| 1307 | + expect(CLASS); | |
| 1308 | + } | |
| 1309 | + Expression e = parseExpression(); | |
| 1310 | + if (token != IDENT) { | |
| 1311 | + expect(IDENT); | |
| 1312 | + } | |
| 1313 | + // declaration: final expr expr | |
| 1314 | + Statement s = parseDeclaration(p, mod, e); | |
| 1315 | + expect(SEMICOLON); | |
| 1316 | + return s; | |
| 1317 | + } | |
| 1318 | + | |
| 1319 | + default: | |
| 1320 | + env.error(pos, "type.expected"); | |
| 1321 | + throw new SyntaxError(); | |
| 1322 | + } | |
| 1323 | + } | |
| 1324 | + | |
| 1325 | + case VOID: | |
| 1326 | + case STATIC: | |
| 1327 | + case PUBLIC: | |
| 1328 | + case PRIVATE: | |
| 1329 | + case TRANSIENT: | |
| 1330 | + // This is the start of something outside a statement | |
| 1331 | + env.error(pos, "statement.expected"); | |
| 1332 | + throw new SyntaxError(); | |
| 1333 | + } | |
| 1334 | + | |
| 1335 | + long p = pos; | |
| 1336 | + Expression e = parseExpression(); | |
| 1337 | + | |
| 1338 | + if (token == IDENT) { | |
| 1339 | + // declaration: expr expr | |
| 1340 | + Statement s = parseDeclaration(p, 0, e); | |
| 1341 | + expect(SEMICOLON); | |
| 1342 | + return s; | |
| 1343 | + } | |
| 1344 | + if (token == COLON) { | |
| 1345 | + // label: id: stat | |
| 1346 | + scan(); | |
| 1347 | + Statement s = parseStatement(); | |
| 1348 | + s.setLabel(env, e); | |
| 1349 | + return s; | |
| 1350 | + } | |
| 1351 | + | |
| 1352 | + // it was just an expression... | |
| 1353 | + topLevelExpression(e); | |
| 1354 | + expect(SEMICOLON); | |
| 1355 | + return new ExpressionStatement(p, e); | |
| 1356 | + } | |
| 1357 | + | |
| 1358 | + protected Statement parseBlockStatement() throws SyntaxError, IOException { | |
| 1359 | + // compound statement: { stat1 stat2 ... statn } | |
| 1360 | + if (token != LBRACE) { | |
| 1361 | + // We're expecting a block statement. But we'll probably do the | |
| 1362 | + // least damage if we try to parse a normal statement instead. | |
| 1363 | + env.error(scanner.prevPos, "token.expected", opNames[LBRACE]); | |
| 1364 | + return parseStatement(); | |
| 1365 | + } | |
| 1366 | + long p = scan(); | |
| 1367 | + int i = argIndex; | |
| 1368 | + while ((token != EOF) && (token != RBRACE)) { | |
| 1369 | + int j = argIndex; | |
| 1370 | + try { | |
| 1371 | + addArgument(parseStatement()); | |
| 1372 | + } catch (SyntaxError e) { | |
| 1373 | + argIndex = j; | |
| 1374 | + if (!recoverStatement()) { | |
| 1375 | + throw e; | |
| 1376 | + } | |
| 1377 | + } | |
| 1378 | + } | |
| 1379 | + | |
| 1380 | + expect(RBRACE); | |
| 1381 | + return new CompoundStatement(p, statArgs(i)); | |
| 1382 | + } | |
| 1383 | + | |
| 1384 | + | |
| 1385 | + /** | |
| 1386 | + * Parse an identifier. ie: a.b.c returns "a.b.c" | |
| 1387 | + * If star is true then "a.b.*" is allowed. | |
| 1388 | + * The return value encodes both the identifier and its location. | |
| 1389 | + */ | |
| 1390 | + protected IdentifierToken parseName(boolean star) throws SyntaxError, IOException { | |
| 1391 | + IdentifierToken res = scanner.getIdToken(); | |
| 1392 | + expect(IDENT); | |
| 1393 | + | |
| 1394 | + if (token != FIELD) { | |
| 1395 | + return res; | |
| 1396 | + } | |
| 1397 | + | |
| 1398 | + StringBuffer buf = new StringBuffer(res.id.toString()); | |
| 1399 | + | |
| 1400 | + while (token == FIELD) { | |
| 1401 | + scan(); | |
| 1402 | + if ((token == MUL) && star) { | |
| 1403 | + scan(); | |
| 1404 | + buf.append(".*"); | |
| 1405 | + break; | |
| 1406 | + } | |
| 1407 | + | |
| 1408 | + buf.append('.'); | |
| 1409 | + if (token == IDENT) { | |
| 1410 | + buf.append(scanner.idValue); | |
| 1411 | + } | |
| 1412 | + expect(IDENT); | |
| 1413 | + } | |
| 1414 | + | |
| 1415 | + res.id = Identifier.lookup(buf.toString()); | |
| 1416 | + return res; | |
| 1417 | + } | |
| 1418 | + /** | |
| 1419 | + * @deprecated | |
| 1420 | + * @see #parseName | |
| 1421 | + */ | |
| 1422 | + @Deprecated | |
| 1423 | + protected Identifier parseIdentifier(boolean star) throws SyntaxError, IOException { | |
| 1424 | + return parseName(star).id; | |
| 1425 | + } | |
| 1426 | + | |
| 1427 | + /** | |
| 1428 | + * Parse a type expression, this results in a Type. | |
| 1429 | + * The parse includes trailing array brackets. | |
| 1430 | + */ | |
| 1431 | + protected Type parseType() throws SyntaxError, IOException { | |
| 1432 | + Type t; | |
| 1433 | + | |
| 1434 | + switch (token) { | |
| 1435 | + case IDENT: | |
| 1436 | + t = Type.tClass(parseName(false).id); | |
| 1437 | + break; | |
| 1438 | + case VOID: | |
| 1439 | + scan(); | |
| 1440 | + t = Type.tVoid; | |
| 1441 | + break; | |
| 1442 | + case BOOLEAN: | |
| 1443 | + scan(); | |
| 1444 | + t = Type.tBoolean; | |
| 1445 | + break; | |
| 1446 | + case BYTE: | |
| 1447 | + scan(); | |
| 1448 | + t = Type.tByte; | |
| 1449 | + break; | |
| 1450 | + case CHAR: | |
| 1451 | + scan(); | |
| 1452 | + t = Type.tChar; | |
| 1453 | + break; | |
| 1454 | + case SHORT: | |
| 1455 | + scan(); | |
| 1456 | + t = Type.tShort; | |
| 1457 | + break; | |
| 1458 | + case INT: | |
| 1459 | + scan(); | |
| 1460 | + t = Type.tInt; | |
| 1461 | + break; | |
| 1462 | + case FLOAT: | |
| 1463 | + scan(); | |
| 1464 | + t = Type.tFloat; | |
| 1465 | + break; | |
| 1466 | + case LONG: | |
| 1467 | + scan(); | |
| 1468 | + t = Type.tLong; | |
| 1469 | + break; | |
| 1470 | + case DOUBLE: | |
| 1471 | + scan(); | |
| 1472 | + t = Type.tDouble; | |
| 1473 | + break; | |
| 1474 | + default: | |
| 1475 | + env.error(pos, "type.expected"); | |
| 1476 | + throw new SyntaxError(); | |
| 1477 | + } | |
| 1478 | + return parseArrayBrackets(t); | |
| 1479 | + } | |
| 1480 | + | |
| 1481 | + /** | |
| 1482 | + * Parse the tail of a type expression, which might be array brackets. | |
| 1483 | + * Return the given type, as possibly modified by the suffix. | |
| 1484 | + */ | |
| 1485 | + protected Type parseArrayBrackets(Type t) throws SyntaxError, IOException { | |
| 1486 | + | |
| 1487 | + // Parse []'s | |
| 1488 | + while (token == LSQBRACKET) { | |
| 1489 | + scan(); | |
| 1490 | + if (token != RSQBRACKET) { | |
| 1491 | + env.error(pos, "array.dim.in.decl"); | |
| 1492 | + parseExpression(); | |
| 1493 | + } | |
| 1494 | + expect(RSQBRACKET); | |
| 1495 | + t = Type.tArray(t); | |
| 1496 | + } | |
| 1497 | + return t; | |
| 1498 | + } | |
| 1499 | + | |
| 1500 | + /* | |
| 1501 | + * Dealing with argument lists, I'm not using | |
| 1502 | + * Vector for efficiency. | |
| 1503 | + */ | |
| 1504 | + | |
| 1505 | + private int aCount = 0; | |
| 1506 | + private Type aTypes[] = new Type[8]; | |
| 1507 | + private IdentifierToken aNames[] = new IdentifierToken[aTypes.length]; | |
| 1508 | + | |
| 1509 | + private void addArgument(int mod, Type t, IdentifierToken nm) { | |
| 1510 | + nm.modifiers = mod; | |
| 1511 | + if (aCount >= aTypes.length) { | |
| 1512 | + Type newATypes[] = new Type[aCount * 2]; | |
| 1513 | + System.arraycopy(aTypes, 0, newATypes, 0, aCount); | |
| 1514 | + aTypes = newATypes; | |
| 1515 | + IdentifierToken newANames[] = new IdentifierToken[aCount * 2]; | |
| 1516 | + System.arraycopy(aNames, 0, newANames, 0, aCount); | |
| 1517 | + aNames = newANames; | |
| 1518 | + } | |
| 1519 | + aTypes[aCount] = t; | |
| 1520 | + aNames[aCount++] = nm; | |
| 1521 | + } | |
| 1522 | + | |
| 1523 | + /** | |
| 1524 | + * Parse a possibly-empty sequence of modifier keywords. | |
| 1525 | + * Return the resulting bitmask. | |
| 1526 | + * Diagnose repeated modifiers, but make no other checks. | |
| 1527 | + * Only modifiers mentioned in the given bitmask are scanned; | |
| 1528 | + * an unmatched modifier must be handled by the caller. | |
| 1529 | + */ | |
| 1530 | + protected int parseModifiers(int mask) throws IOException { | |
| 1531 | + int mod = 0; | |
| 1532 | + while (true) { | |
| 1533 | + if (token==CONST) { | |
| 1534 | + // const isn't in java, but handle a common C++ usage gently | |
| 1535 | + env.error(pos, "not.supported", "const"); | |
| 1536 | + scan(); | |
| 1537 | + } | |
| 1538 | + int nextmod = 0; | |
| 1539 | + switch (token) { | |
| 1540 | + case PRIVATE: nextmod = M_PRIVATE; break; | |
| 1541 | + case PUBLIC: nextmod = M_PUBLIC; break; | |
| 1542 | + case PROTECTED: nextmod = M_PROTECTED; break; | |
| 1543 | + case STATIC: nextmod = M_STATIC; break; | |
| 1544 | + case TRANSIENT: nextmod = M_TRANSIENT; break; | |
| 1545 | + case FINAL: nextmod = M_FINAL; break; | |
| 1546 | + case ABSTRACT: nextmod = M_ABSTRACT; break; | |
| 1547 | + case NATIVE: nextmod = M_NATIVE; break; | |
| 1548 | + case VOLATILE: nextmod = M_VOLATILE; break; | |
| 1549 | + case SYNCHRONIZED: nextmod = M_SYNCHRONIZED; break; | |
| 1550 | + case STRICTFP: nextmod = M_STRICTFP; break; | |
| 1551 | + } | |
| 1552 | + if ((nextmod & mask) == 0) { | |
| 1553 | + break; | |
| 1554 | + } | |
| 1555 | + if ((nextmod & mod) != 0) { | |
| 1556 | + env.error(pos, "repeated.modifier"); | |
| 1557 | + } | |
| 1558 | + mod |= nextmod; | |
| 1559 | + scan(); | |
| 1560 | + } | |
| 1561 | + return mod; | |
| 1562 | + } | |
| 1563 | + | |
| 1564 | + private ClassDefinition curClass; | |
| 1565 | + | |
| 1566 | + /** | |
| 1567 | + * Parse a field. | |
| 1568 | + */ | |
| 1569 | + protected void parseField() throws SyntaxError, IOException { | |
| 1570 | + | |
| 1571 | + // Empty fields are not allowed by the JLS but are accepted by | |
| 1572 | + // the compiler, and much code has come to rely on this. It has | |
| 1573 | + // been decided that the language will be extended to legitimize them. | |
| 1574 | + if (token == SEMICOLON) { | |
| 1575 | + // empty field | |
| 1576 | + scan(); | |
| 1577 | + return; | |
| 1578 | + } | |
| 1579 | + | |
| 1580 | + // Optional doc comment | |
| 1581 | + String doc = scanner.docComment; | |
| 1582 | + | |
| 1583 | + // The start of the field | |
| 1584 | + long p = pos; | |
| 1585 | + | |
| 1586 | + // Parse the modifiers | |
| 1587 | + int mod = parseModifiers(MM_FIELD | MM_METHOD); | |
| 1588 | + | |
| 1589 | + // Check for static initializer | |
| 1590 | + // ie: static { ... } | |
| 1591 | + // or an instance initializer (w/o the static). | |
| 1592 | + if ((mod == (mod & M_STATIC)) && (token == LBRACE)) { | |
| 1593 | + // static initializer | |
| 1594 | + actions.defineField(p, curClass, doc, mod, | |
| 1595 | + Type.tMethod(Type.tVoid), | |
| 1596 | + new IdentifierToken(idClassInit), null, null, | |
| 1597 | + parseStatement()); | |
| 1598 | + return; | |
| 1599 | + } | |
| 1600 | + | |
| 1601 | + // Check for inner class | |
| 1602 | + if (token == CLASS || token == INTERFACE) { | |
| 1603 | + parseNamedClass(mod, CLASS, doc); | |
| 1604 | + return; | |
| 1605 | + } | |
| 1606 | + | |
| 1607 | + // Parse the type | |
| 1608 | + p = pos; | |
| 1609 | + Type t = parseType(); | |
| 1610 | + IdentifierToken id = null; | |
| 1611 | + | |
| 1612 | + // Check that the type is followed by an Identifier | |
| 1613 | + // (the name of the method or the first variable), | |
| 1614 | + // otherwise it is a constructor. | |
| 1615 | + switch (token) { | |
| 1616 | + case IDENT: | |
| 1617 | + id = scanner.getIdToken(); | |
| 1618 | + p = scan(); | |
| 1619 | + break; | |
| 1620 | + | |
| 1621 | + case LPAREN: | |
| 1622 | + // It is a constructor | |
| 1623 | + id = new IdentifierToken(idInit); | |
| 1624 | + if ((mod & M_STRICTFP) != 0) | |
| 1625 | + env.error(pos, "bad.constructor.modifier"); | |
| 1626 | + break; | |
| 1627 | + | |
| 1628 | + default: | |
| 1629 | + expect(IDENT); | |
| 1630 | + } | |
| 1631 | + | |
| 1632 | + // If the next token is a left-bracket then we | |
| 1633 | + // are dealing with a method or constructor, otherwise it is | |
| 1634 | + // a list of variables | |
| 1635 | + if (token == LPAREN) { | |
| 1636 | + // It is a method or constructor declaration | |
| 1637 | + scan(); | |
| 1638 | + aCount = 0; | |
| 1639 | + | |
| 1640 | + if (token != RPAREN) { | |
| 1641 | + // Parse argument type and identifier | |
| 1642 | + // (arguments (like locals) are allowed to be final) | |
| 1643 | + int am = parseModifiers(M_FINAL); | |
| 1644 | + Type at = parseType(); | |
| 1645 | + IdentifierToken an = scanner.getIdToken(); | |
| 1646 | + expect(IDENT); | |
| 1647 | + | |
| 1648 | + // Parse optional array specifier, ie: a[][] | |
| 1649 | + at = parseArrayBrackets(at); | |
| 1650 | + addArgument(am, at, an); | |
| 1651 | + | |
| 1652 | + // If the next token is a comma then there are | |
| 1653 | + // more arguments | |
| 1654 | + while (token == COMMA) { | |
| 1655 | + // Parse argument type and identifier | |
| 1656 | + scan(); | |
| 1657 | + am = parseModifiers(M_FINAL); | |
| 1658 | + at = parseType(); | |
| 1659 | + an = scanner.getIdToken(); | |
| 1660 | + expect(IDENT); | |
| 1661 | + | |
| 1662 | + // Parse optional array specifier, ie: a[][] | |
| 1663 | + at = parseArrayBrackets(at); | |
| 1664 | + addArgument(am, at, an); | |
| 1665 | + } | |
| 1666 | + } | |
| 1667 | + expect(RPAREN); | |
| 1668 | + | |
| 1669 | + // Parse optional array sepecifier, ie: foo()[][] | |
| 1670 | + t = parseArrayBrackets(t); | |
| 1671 | + | |
| 1672 | + // copy arguments | |
| 1673 | + Type atypes[] = new Type[aCount]; | |
| 1674 | + System.arraycopy(aTypes, 0, atypes, 0, aCount); | |
| 1675 | + | |
| 1676 | + IdentifierToken anames[] = new IdentifierToken[aCount]; | |
| 1677 | + System.arraycopy(aNames, 0, anames, 0, aCount); | |
| 1678 | + | |
| 1679 | + // Construct the type signature | |
| 1680 | + t = Type.tMethod(t, atypes); | |
| 1681 | + | |
| 1682 | + // Parse and ignore throws clause | |
| 1683 | + IdentifierToken exp[] = null; | |
| 1684 | + if (token == THROWS) { | |
| 1685 | + Vector v = new Vector(); | |
| 1686 | + scan(); | |
| 1687 | + v.addElement(parseName(false)); | |
| 1688 | + while (token == COMMA) { | |
| 1689 | + scan(); | |
| 1690 | + v.addElement(parseName(false)); | |
| 1691 | + } | |
| 1692 | + | |
| 1693 | + exp = new IdentifierToken[v.size()]; | |
| 1694 | + v.copyInto(exp); | |
| 1695 | + } | |
| 1696 | + | |
| 1697 | + // Check if it is a method definition or a method declaration | |
| 1698 | + // ie: foo() {...} or foo(); | |
| 1699 | + switch (token) { | |
| 1700 | + case LBRACE: // It's a method definition | |
| 1701 | + | |
| 1702 | + // Set the state of FP strictness for the body of the method | |
| 1703 | + int oldFPstate = FPstate; | |
| 1704 | + if ((mod & M_STRICTFP)!=0) { | |
| 1705 | + FPstate = M_STRICTFP; | |
| 1706 | + } else { | |
| 1707 | + mod |= FPstate & M_STRICTFP; | |
| 1708 | + } | |
| 1709 | + | |
| 1710 | + actions.defineField(p, curClass, doc, mod, t, id, | |
| 1711 | + anames, exp, parseStatement()); | |
| 1712 | + | |
| 1713 | + FPstate = oldFPstate; | |
| 1714 | + | |
| 1715 | + break; | |
| 1716 | + | |
| 1717 | + case SEMICOLON: | |
| 1718 | + scan(); | |
| 1719 | + actions.defineField(p, curClass, doc, mod, t, id, | |
| 1720 | + anames, exp, null); | |
| 1721 | + break; | |
| 1722 | + | |
| 1723 | + default: | |
| 1724 | + // really expected a statement body here | |
| 1725 | + if ((mod & (M_NATIVE | M_ABSTRACT)) == 0) { | |
| 1726 | + expect(LBRACE); | |
| 1727 | + } else { | |
| 1728 | + expect(SEMICOLON); | |
| 1729 | + } | |
| 1730 | + } | |
| 1731 | + return; | |
| 1732 | + } | |
| 1733 | + | |
| 1734 | + // It is a list of instance variables | |
| 1735 | + while (true) { | |
| 1736 | + p = pos; // get the current position | |
| 1737 | + // parse the array brackets (if any) | |
| 1738 | + // ie: var[][][] | |
| 1739 | + Type vt = parseArrayBrackets(t); | |
| 1740 | + | |
| 1741 | + // Parse the optional initializer | |
| 1742 | + Node init = null; | |
| 1743 | + if (token == ASSIGN) { | |
| 1744 | + scan(); | |
| 1745 | + init = parseExpression(); | |
| 1746 | + } | |
| 1747 | + | |
| 1748 | + // Define the variable | |
| 1749 | + actions.defineField(p, curClass, doc, mod, vt, id, | |
| 1750 | + null, null, init); | |
| 1751 | + | |
| 1752 | + // If the next token is a comma, then there is more | |
| 1753 | + if (token != COMMA) { | |
| 1754 | + expect(SEMICOLON); | |
| 1755 | + return; | |
| 1756 | + } | |
| 1757 | + scan(); | |
| 1758 | + | |
| 1759 | + // The next token must be an identifier | |
| 1760 | + id = scanner.getIdToken(); | |
| 1761 | + expect(IDENT); | |
| 1762 | + } | |
| 1763 | + } | |
| 1764 | + | |
| 1765 | + /** | |
| 1766 | + * Recover after a syntax error in a field. This involves | |
| 1767 | + * discarding tokens until an EOF or a possible legal | |
| 1768 | + * continuation is encountered. | |
| 1769 | + */ | |
| 1770 | + protected void recoverField(ClassDefinition newClass) throws SyntaxError, IOException { | |
| 1771 | + while (true) { | |
| 1772 | + switch (token) { | |
| 1773 | + case EOF: | |
| 1774 | + case STATIC: | |
| 1775 | + case FINAL: | |
| 1776 | + case PUBLIC: | |
| 1777 | + case PRIVATE: | |
| 1778 | + case SYNCHRONIZED: | |
| 1779 | + case TRANSIENT: | |
| 1780 | + | |
| 1781 | + case VOID: | |
| 1782 | + case BOOLEAN: | |
| 1783 | + case BYTE: | |
| 1784 | + case CHAR: | |
| 1785 | + case SHORT: | |
| 1786 | + case INT: | |
| 1787 | + case FLOAT: | |
| 1788 | + case LONG: | |
| 1789 | + case DOUBLE: | |
| 1790 | + // possible begin of a field, continue | |
| 1791 | + return; | |
| 1792 | + | |
| 1793 | + case LBRACE: | |
| 1794 | + match(LBRACE, RBRACE); | |
| 1795 | + scan(); | |
| 1796 | + break; | |
| 1797 | + | |
| 1798 | + case LPAREN: | |
| 1799 | + match(LPAREN, RPAREN); | |
| 1800 | + scan(); | |
| 1801 | + break; | |
| 1802 | + | |
| 1803 | + case LSQBRACKET: | |
| 1804 | + match(LSQBRACKET, RSQBRACKET); | |
| 1805 | + scan(); | |
| 1806 | + break; | |
| 1807 | + | |
| 1808 | + case RBRACE: | |
| 1809 | + case INTERFACE: | |
| 1810 | + case CLASS: | |
| 1811 | + case IMPORT: | |
| 1812 | + case PACKAGE: | |
| 1813 | + // begin of something outside a class, panic more | |
| 1814 | + actions.endClass(pos, newClass); | |
| 1815 | + throw new SyntaxError(); | |
| 1816 | + | |
| 1817 | + default: | |
| 1818 | + // don't know what to do, skip | |
| 1819 | + scan(); | |
| 1820 | + break; | |
| 1821 | + } | |
| 1822 | + } | |
| 1823 | + } | |
| 1824 | + | |
| 1825 | + /** | |
| 1826 | + * Parse a top-level class or interface declaration. | |
| 1827 | + */ | |
| 1828 | + protected void parseClass() throws SyntaxError, IOException { | |
| 1829 | + String doc = scanner.docComment; | |
| 1830 | + | |
| 1831 | + // Parse the modifiers. | |
| 1832 | + int mod = parseModifiers(MM_CLASS | MM_MEMBER); | |
| 1833 | + | |
| 1834 | + parseNamedClass(mod, PACKAGE, doc); | |
| 1835 | + } | |
| 1836 | + | |
| 1837 | + // Current strict/default state of floating point. This is | |
| 1838 | + // set and reset with a stack discipline around methods and named | |
| 1839 | + // classes. Only M_STRICTFP may be set in this word. try... | |
| 1840 | + // finally is not needed to protect setting and resetting because | |
| 1841 | + // there are no error messages based on FPstate. | |
| 1842 | + private int FPstate = 0; | |
| 1843 | + | |
| 1844 | + /** | |
| 1845 | + * Parse a block-local class or interface declaration. | |
| 1846 | + */ | |
| 1847 | + protected Statement parseLocalClass(int mod) throws SyntaxError, IOException { | |
| 1848 | + long p = pos; | |
| 1849 | + ClassDefinition body = parseNamedClass(M_LOCAL | mod, STAT, null); | |
| 1850 | + Statement ds[] = { | |
| 1851 | + new VarDeclarationStatement(p, new LocalMember(body), null) | |
| 1852 | + }; | |
| 1853 | + Expression type = new TypeExpression(p, body.getType()); | |
| 1854 | + return new DeclarationStatement(p, 0, type, ds); | |
| 1855 | + } | |
| 1856 | + | |
| 1857 | + /** | |
| 1858 | + * Parse a named class or interface declaration, | |
| 1859 | + * starting at "class" or "interface". | |
| 1860 | + * @arg ctx Syntactic context of the class, one of {PACKAGE CLASS STAT EXPR}. | |
| 1861 | + */ | |
| 1862 | + protected ClassDefinition parseNamedClass(int mod, int ctx, String doc) throws SyntaxError, IOException { | |
| 1863 | + // Parse class/interface | |
| 1864 | + switch (token) { | |
| 1865 | + case INTERFACE: | |
| 1866 | + scan(); | |
| 1867 | + mod |= M_INTERFACE; | |
| 1868 | + break; | |
| 1869 | + | |
| 1870 | + case CLASS: | |
| 1871 | + scan(); | |
| 1872 | + break; | |
| 1873 | + | |
| 1874 | + default: | |
| 1875 | + env.error(pos, "class.expected"); | |
| 1876 | + break; | |
| 1877 | + } | |
| 1878 | + | |
| 1879 | + int oldFPstate = FPstate; | |
| 1880 | + if ((mod & M_STRICTFP)!=0) { | |
| 1881 | + FPstate = M_STRICTFP; | |
| 1882 | + } else { | |
| 1883 | + // The & (...) isn't really necessary here because we do maintain | |
| 1884 | + // the invariant that FPstate has no extra bits set. | |
| 1885 | + mod |= FPstate & M_STRICTFP; | |
| 1886 | + } | |
| 1887 | + | |
| 1888 | + // Parse the class name | |
| 1889 | + IdentifierToken nm = scanner.getIdToken(); | |
| 1890 | + long p = pos; | |
| 1891 | + expect(IDENT); | |
| 1892 | + | |
| 1893 | + Vector ext = new Vector(); | |
| 1894 | + Vector impl = new Vector(); | |
| 1895 | + parseInheritance(ext, impl); | |
| 1896 | + | |
| 1897 | + ClassDefinition tmp = parseClassBody(nm, mod, ctx, doc, ext, impl, p); | |
| 1898 | + | |
| 1899 | + FPstate = oldFPstate; | |
| 1900 | + | |
| 1901 | + return tmp; | |
| 1902 | + } | |
| 1903 | + | |
| 1904 | + protected void parseInheritance(Vector ext, Vector impl) throws SyntaxError, IOException { | |
| 1905 | + // Parse extends clause | |
| 1906 | + if (token == EXTENDS) { | |
| 1907 | + scan(); | |
| 1908 | + ext.addElement(parseName(false)); | |
| 1909 | + while (token == COMMA) { | |
| 1910 | + scan(); | |
| 1911 | + ext.addElement(parseName(false)); | |
| 1912 | + } | |
| 1913 | + } | |
| 1914 | + | |
| 1915 | + // Parse implements clause | |
| 1916 | + if (token == IMPLEMENTS) { | |
| 1917 | + scan(); | |
| 1918 | + impl.addElement(parseName(false)); | |
| 1919 | + while (token == COMMA) { | |
| 1920 | + scan(); | |
| 1921 | + impl.addElement(parseName(false)); | |
| 1922 | + } | |
| 1923 | + } | |
| 1924 | + } | |
| 1925 | + | |
| 1926 | + /** | |
| 1927 | + * Parse the body of a class or interface declaration, | |
| 1928 | + * starting at the left brace. | |
| 1929 | + */ | |
| 1930 | + protected ClassDefinition parseClassBody(IdentifierToken nm, int mod, | |
| 1931 | + int ctx, String doc, | |
| 1932 | + Vector ext, Vector impl, long p | |
| 1933 | + ) throws SyntaxError, IOException { | |
| 1934 | + // Decide which is the super class | |
| 1935 | + IdentifierToken sup = null; | |
| 1936 | + if ((mod & M_INTERFACE) != 0) { | |
| 1937 | + if (impl.size() > 0) { | |
| 1938 | + env.error(((IdentifierToken)impl.elementAt(0)).getWhere(), | |
| 1939 | + "intf.impl.intf"); | |
| 1940 | + } | |
| 1941 | + impl = ext; | |
| 1942 | + } else { | |
| 1943 | + if (ext.size() > 0) { | |
| 1944 | + if (ext.size() > 1) { | |
| 1945 | + env.error(((IdentifierToken)ext.elementAt(1)).getWhere(), | |
| 1946 | + "multiple.inherit"); | |
| 1947 | + } | |
| 1948 | + sup = (IdentifierToken)ext.elementAt(0); | |
| 1949 | + } | |
| 1950 | + } | |
| 1951 | + | |
| 1952 | + ClassDefinition oldClass = curClass; | |
| 1953 | + | |
| 1954 | + // Begin a new class | |
| 1955 | + IdentifierToken implids[] = new IdentifierToken[impl.size()]; | |
| 1956 | + impl.copyInto(implids); | |
| 1957 | + ClassDefinition newClass = | |
| 1958 | + actions.beginClass(p, doc, mod, nm, sup, implids); | |
| 1959 | + | |
| 1960 | + // Parse fields | |
| 1961 | + expect(LBRACE); | |
| 1962 | + while ((token != EOF) && (token != RBRACE)) { | |
| 1963 | + try { | |
| 1964 | + curClass = newClass; | |
| 1965 | + parseField(); | |
| 1966 | + } catch (SyntaxError e) { | |
| 1967 | + recoverField(newClass); | |
| 1968 | + } finally { | |
| 1969 | + curClass = oldClass; | |
| 1970 | + } | |
| 1971 | + } | |
| 1972 | + expect(RBRACE); | |
| 1973 | + | |
| 1974 | + // End the class | |
| 1975 | + actions.endClass(scanner.prevPos, newClass); | |
| 1976 | + return newClass; | |
| 1977 | + } | |
| 1978 | + | |
| 1979 | + /** | |
| 1980 | + * Recover after a syntax error in the file. | |
| 1981 | + * This involves discarding tokens until an EOF | |
| 1982 | + * or a possible legal continuation is encountered. | |
| 1983 | + */ | |
| 1984 | + protected void recoverFile() throws IOException { | |
| 1985 | + while (true) { | |
| 1986 | + switch (token) { | |
| 1987 | + case CLASS: | |
| 1988 | + case INTERFACE: | |
| 1989 | + // Start of a new source file statement, continue | |
| 1990 | + return; | |
| 1991 | + | |
| 1992 | + case LBRACE: | |
| 1993 | + match(LBRACE, RBRACE); | |
| 1994 | + scan(); | |
| 1995 | + break; | |
| 1996 | + | |
| 1997 | + case LPAREN: | |
| 1998 | + match(LPAREN, RPAREN); | |
| 1999 | + scan(); | |
| 2000 | + break; | |
| 2001 | + | |
| 2002 | + case LSQBRACKET: | |
| 2003 | + match(LSQBRACKET, RSQBRACKET); | |
| 2004 | + scan(); | |
| 2005 | + break; | |
| 2006 | + | |
| 2007 | + case EOF: | |
| 2008 | + return; | |
| 2009 | + | |
| 2010 | + default: | |
| 2011 | + // Don't know what to do, skip | |
| 2012 | + scan(); | |
| 2013 | + break; | |
| 2014 | + } | |
| 2015 | + } | |
| 2016 | + } | |
| 2017 | + | |
| 2018 | + /** | |
| 2019 | + * Parse an Java file. | |
| 2020 | + */ | |
| 2021 | + public void parseFile() { | |
| 2022 | + try { | |
| 2023 | + try { | |
| 2024 | + if (token == PACKAGE) { | |
| 2025 | + // Package statement | |
| 2026 | + long p = scan(); | |
| 2027 | + IdentifierToken id = parseName(false); | |
| 2028 | + expect(SEMICOLON); | |
| 2029 | + actions.packageDeclaration(p, id); | |
| 2030 | + } | |
| 2031 | + } catch (SyntaxError e) { | |
| 2032 | + recoverFile(); | |
| 2033 | + } | |
| 2034 | + while (token == IMPORT) { | |
| 2035 | + try{ | |
| 2036 | + // Import statement | |
| 2037 | + long p = scan(); | |
| 2038 | + IdentifierToken id = parseName(true); | |
| 2039 | + expect(SEMICOLON); | |
| 2040 | + if (id.id.getName().equals(idStar)) { | |
| 2041 | + id.id = id.id.getQualifier(); | |
| 2042 | + actions.importPackage(p, id); | |
| 2043 | + } else { | |
| 2044 | + actions.importClass(p, id); | |
| 2045 | + } | |
| 2046 | + } catch (SyntaxError e) { | |
| 2047 | + recoverFile(); | |
| 2048 | + } | |
| 2049 | + } | |
| 2050 | + | |
| 2051 | + while (token != EOF) { | |
| 2052 | + try { | |
| 2053 | + switch (token) { | |
| 2054 | + case FINAL: | |
| 2055 | + case PUBLIC: | |
| 2056 | + case PRIVATE: | |
| 2057 | + case ABSTRACT: | |
| 2058 | + case CLASS: | |
| 2059 | + case INTERFACE: | |
| 2060 | + case STRICTFP: | |
| 2061 | + // Start of a class | |
| 2062 | + parseClass(); | |
| 2063 | + break; | |
| 2064 | + | |
| 2065 | + case SEMICOLON: | |
| 2066 | + // Bogus semicolon. | |
| 2067 | + // According to the JLS (7.6,19.6), a TypeDeclaration | |
| 2068 | + // may consist of a single semicolon, however, this | |
| 2069 | + // usage is discouraged (JLS 7.6). In contrast, | |
| 2070 | + // a FieldDeclaration may not be empty, and is flagged | |
| 2071 | + // as an error. See parseField above. | |
| 2072 | + scan(); | |
| 2073 | + break; | |
| 2074 | + | |
| 2075 | + case EOF: | |
| 2076 | + // The end | |
| 2077 | + return; | |
| 2078 | + | |
| 2079 | + default: | |
| 2080 | + // Oops | |
| 2081 | + env.error(pos, "toplevel.expected"); | |
| 2082 | + throw new SyntaxError(); | |
| 2083 | + } | |
| 2084 | + } catch (SyntaxError e) { | |
| 2085 | + recoverFile(); | |
| 2086 | + } | |
| 2087 | + } | |
| 2088 | + } catch (IOException e) { | |
| 2089 | + env.error(pos, "io.exception", env.getSource()); | |
| 2090 | + return; | |
| 2091 | + } | |
| 2092 | + } | |
| 2093 | + | |
| 2094 | + /** | |
| 2095 | + * Usually <code>this.scanner == (Scanner)this</code>. | |
| 2096 | + * However, a delegate scanner can produce tokens for this parser, | |
| 2097 | + * in which case <code>(Scanner)this</code> is unused, | |
| 2098 | + * except for <code>this.token</code> and <code>this.pos</code> | |
| 2099 | + * instance variables which are filled from the real scanner | |
| 2100 | + * by <code>this.scan()</code> and the constructor. | |
| 2101 | + */ | |
| 2102 | + protected Scanner scanner; | |
| 2103 | + | |
| 2104 | + // Design Note: We ought to disinherit Parser from Scanner. | |
| 2105 | + // We also should split out the interface ParserActions from | |
| 2106 | + // Parser, and make BatchParser implement ParserActions, | |
| 2107 | + // not extend Parser. This would split scanning, parsing, | |
| 2108 | + // and class building into distinct responsibility areas. | |
| 2109 | + // (Perhaps tree building could be virtualized too.) | |
| 2110 | + | |
| 2111 | + public long scan() throws IOException { | |
| 2112 | + if (scanner != this && scanner != null) { | |
| 2113 | + long result = scanner.scan(); | |
| 2114 | + ((Scanner)this).token = scanner.token; | |
| 2115 | + ((Scanner)this).pos = scanner.pos; | |
| 2116 | + return result; | |
| 2117 | + } | |
| 2118 | + return super.scan(); | |
| 2119 | + } | |
| 2120 | + | |
| 2121 | + public void match(int open, int close) throws IOException { | |
| 2122 | + if (scanner != this) { | |
| 2123 | + scanner.match(open, close); | |
| 2124 | + ((Scanner)this).token = scanner.token; | |
| 2125 | + ((Scanner)this).pos = scanner.pos; | |
| 2126 | + return; | |
| 2127 | + } | |
| 2128 | + super.match(open, close); | |
| 2129 | + } | |
| 2130 | +} | |
| @@ -0,0 +1,87 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +import sun.tools.tree.*; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * This is the protocol by which a Parser makes callbacks | |
| 32 | + * to the later phases of the compiler. | |
| 33 | + * <p> | |
| 34 | + * (As a backwards compatibility trick, Parser implements | |
| 35 | + * this protocol, so that an instance of a Parser subclass | |
| 36 | + * can handle its own actions. The preferred way to use a | |
| 37 | + * Parser, however, is to instantiate it directly with a | |
| 38 | + * reference to your own ParserActions implementation.) | |
| 39 | + * | |
| 40 | + * WARNING: The contents of this source file are not part of any | |
| 41 | + * supported API. Code that depends on them does so at its own risk: | |
| 42 | + * they are subject to change or removal without notice. | |
| 43 | + * | |
| 44 | + * @author John R. Rose | |
| 45 | + */ | |
| 46 | +public interface ParserActions { | |
| 47 | + /** | |
| 48 | + * package declaration | |
| 49 | + */ | |
| 50 | + void packageDeclaration(long off, IdentifierToken nm); | |
| 51 | + | |
| 52 | + /** | |
| 53 | + * import class | |
| 54 | + */ | |
| 55 | + void importClass(long off, IdentifierToken nm); | |
| 56 | + | |
| 57 | + /** | |
| 58 | + * import package | |
| 59 | + */ | |
| 60 | + void importPackage(long off, IdentifierToken nm); | |
| 61 | + | |
| 62 | + /** | |
| 63 | + * Define class | |
| 64 | + * @return a cookie for the class | |
| 65 | + * This cookie is used by the parser when calling defineField | |
| 66 | + * and endClass, and is not examined otherwise. | |
| 67 | + */ | |
| 68 | + ClassDefinition beginClass(long off, String doc, | |
| 69 | + int mod, IdentifierToken nm, | |
| 70 | + IdentifierToken sup, IdentifierToken impl[]); | |
| 71 | + | |
| 72 | + | |
| 73 | + /** | |
| 74 | + * End class | |
| 75 | + * @param c a cookie returned by the corresponding beginClass call | |
| 76 | + */ | |
| 77 | + void endClass(long off, ClassDefinition c); | |
| 78 | + | |
| 79 | + /** | |
| 80 | + * Define a field | |
| 81 | + * @param c a cookie returned by the corresponding beginClass call | |
| 82 | + */ | |
| 83 | + void defineField(long where, ClassDefinition c, | |
| 84 | + String doc, int mod, Type t, | |
| 85 | + IdentifierToken nm, IdentifierToken args[], | |
| 86 | + IdentifierToken exp[], Node val); | |
| 87 | +} | |
| @@ -0,0 +1,739 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * WARNING: The contents of this source file are not part of any | |
| 30 | + * supported API. Code that depends on them does so at its own risk: | |
| 31 | + * they are subject to change or removal without notice. | |
| 32 | + */ | |
| 33 | +public interface RuntimeConstants { | |
| 34 | + | |
| 35 | + /* Signature Characters */ | |
| 36 | + char SIGC_VOID = 'V'; | |
| 37 | + String SIG_VOID = "V"; | |
| 38 | + char SIGC_BOOLEAN = 'Z'; | |
| 39 | + String SIG_BOOLEAN = "Z"; | |
| 40 | + char SIGC_BYTE = 'B'; | |
| 41 | + String SIG_BYTE = "B"; | |
| 42 | + char SIGC_CHAR = 'C'; | |
| 43 | + String SIG_CHAR = "C"; | |
| 44 | + char SIGC_SHORT = 'S'; | |
| 45 | + String SIG_SHORT = "S"; | |
| 46 | + char SIGC_INT = 'I'; | |
| 47 | + String SIG_INT = "I"; | |
| 48 | + char SIGC_LONG = 'J'; | |
| 49 | + String SIG_LONG = "J"; | |
| 50 | + char SIGC_FLOAT = 'F'; | |
| 51 | + String SIG_FLOAT = "F"; | |
| 52 | + char SIGC_DOUBLE = 'D'; | |
| 53 | + String SIG_DOUBLE = "D"; | |
| 54 | + char SIGC_ARRAY = '['; | |
| 55 | + String SIG_ARRAY = "["; | |
| 56 | + char SIGC_CLASS = 'L'; | |
| 57 | + String SIG_CLASS = "L"; | |
| 58 | + char SIGC_METHOD = '('; | |
| 59 | + String SIG_METHOD = "("; | |
| 60 | + char SIGC_ENDCLASS = ';'; | |
| 61 | + String SIG_ENDCLASS = ";"; | |
| 62 | + char SIGC_ENDMETHOD = ')'; | |
| 63 | + String SIG_ENDMETHOD = ")"; | |
| 64 | + char SIGC_PACKAGE = '/'; | |
| 65 | + String SIG_PACKAGE = "/"; | |
| 66 | + | |
| 67 | + /* Class File Constants */ | |
| 68 | + int JAVA_MAGIC = 0xcafebabe; | |
| 69 | + int JAVA_MIN_SUPPORTED_VERSION = 45; | |
| 70 | + int JAVA_MAX_SUPPORTED_VERSION = 51; | |
| 71 | + int JAVA_MAX_SUPPORTED_MINOR_VERSION = 0; | |
| 72 | + | |
| 73 | + /* Generate class file version for 1.1 by default */ | |
| 74 | + int JAVA_DEFAULT_VERSION = 45; | |
| 75 | + int JAVA_DEFAULT_MINOR_VERSION = 3; | |
| 76 | + | |
| 77 | + /* Constant table */ | |
| 78 | + int CONSTANT_UTF8 = 1; | |
| 79 | + int CONSTANT_UNICODE = 2; | |
| 80 | + int CONSTANT_INTEGER = 3; | |
| 81 | + int CONSTANT_FLOAT = 4; | |
| 82 | + int CONSTANT_LONG = 5; | |
| 83 | + int CONSTANT_DOUBLE = 6; | |
| 84 | + int CONSTANT_CLASS = 7; | |
| 85 | + int CONSTANT_STRING = 8; | |
| 86 | + int CONSTANT_FIELD = 9; | |
| 87 | + int CONSTANT_METHOD = 10; | |
| 88 | + int CONSTANT_INTERFACEMETHOD = 11; | |
| 89 | + int CONSTANT_NAMEANDTYPE = 12; | |
| 90 | + | |
| 91 | + /* Access and modifier flags */ | |
| 92 | + int ACC_PUBLIC = 0x00000001; | |
| 93 | + int ACC_PRIVATE = 0x00000002; | |
| 94 | + int ACC_PROTECTED = 0x00000004; | |
| 95 | + int ACC_STATIC = 0x00000008; | |
| 96 | + int ACC_FINAL = 0x00000010; | |
| 97 | + int ACC_SYNCHRONIZED = 0x00000020; | |
| 98 | + int ACC_VOLATILE = 0x00000040; | |
| 99 | + int ACC_TRANSIENT = 0x00000080; | |
| 100 | + int ACC_NATIVE = 0x00000100; | |
| 101 | + int ACC_INTERFACE = 0x00000200; | |
| 102 | + int ACC_ABSTRACT = 0x00000400; | |
| 103 | + int ACC_SUPER = 0x00000020; | |
| 104 | + int ACC_STRICT = 0x00000800; | |
| 105 | + | |
| 106 | + /* Type codes */ | |
| 107 | + int T_CLASS = 0x00000002; | |
| 108 | + int T_BOOLEAN = 0x00000004; | |
| 109 | + int T_CHAR = 0x00000005; | |
| 110 | + int T_FLOAT = 0x00000006; | |
| 111 | + int T_DOUBLE = 0x00000007; | |
| 112 | + int T_BYTE = 0x00000008; | |
| 113 | + int T_SHORT = 0x00000009; | |
| 114 | + int T_INT = 0x0000000a; | |
| 115 | + int T_LONG = 0x0000000b; | |
| 116 | + | |
| 117 | + /* Opcodes */ | |
| 118 | + int opc_try = -3; | |
| 119 | + int opc_dead = -2; | |
| 120 | + int opc_label = -1; | |
| 121 | + int opc_nop = 0; | |
| 122 | + int opc_aconst_null = 1; | |
| 123 | + int opc_iconst_m1 = 2; | |
| 124 | + int opc_iconst_0 = 3; | |
| 125 | + int opc_iconst_1 = 4; | |
| 126 | + int opc_iconst_2 = 5; | |
| 127 | + int opc_iconst_3 = 6; | |
| 128 | + int opc_iconst_4 = 7; | |
| 129 | + int opc_iconst_5 = 8; | |
| 130 | + int opc_lconst_0 = 9; | |
| 131 | + int opc_lconst_1 = 10; | |
| 132 | + int opc_fconst_0 = 11; | |
| 133 | + int opc_fconst_1 = 12; | |
| 134 | + int opc_fconst_2 = 13; | |
| 135 | + int opc_dconst_0 = 14; | |
| 136 | + int opc_dconst_1 = 15; | |
| 137 | + int opc_bipush = 16; | |
| 138 | + int opc_sipush = 17; | |
| 139 | + int opc_ldc = 18; | |
| 140 | + int opc_ldc_w = 19; | |
| 141 | + int opc_ldc2_w = 20; | |
| 142 | + int opc_iload = 21; | |
| 143 | + int opc_lload = 22; | |
| 144 | + int opc_fload = 23; | |
| 145 | + int opc_dload = 24; | |
| 146 | + int opc_aload = 25; | |
| 147 | + int opc_iload_0 = 26; | |
| 148 | + int opc_iload_1 = 27; | |
| 149 | + int opc_iload_2 = 28; | |
| 150 | + int opc_iload_3 = 29; | |
| 151 | + int opc_lload_0 = 30; | |
| 152 | + int opc_lload_1 = 31; | |
| 153 | + int opc_lload_2 = 32; | |
| 154 | + int opc_lload_3 = 33; | |
| 155 | + int opc_fload_0 = 34; | |
| 156 | + int opc_fload_1 = 35; | |
| 157 | + int opc_fload_2 = 36; | |
| 158 | + int opc_fload_3 = 37; | |
| 159 | + int opc_dload_0 = 38; | |
| 160 | + int opc_dload_1 = 39; | |
| 161 | + int opc_dload_2 = 40; | |
| 162 | + int opc_dload_3 = 41; | |
| 163 | + int opc_aload_0 = 42; | |
| 164 | + int opc_aload_1 = 43; | |
| 165 | + int opc_aload_2 = 44; | |
| 166 | + int opc_aload_3 = 45; | |
| 167 | + int opc_iaload = 46; | |
| 168 | + int opc_laload = 47; | |
| 169 | + int opc_faload = 48; | |
| 170 | + int opc_daload = 49; | |
| 171 | + int opc_aaload = 50; | |
| 172 | + int opc_baload = 51; | |
| 173 | + int opc_caload = 52; | |
| 174 | + int opc_saload = 53; | |
| 175 | + int opc_istore = 54; | |
| 176 | + int opc_lstore = 55; | |
| 177 | + int opc_fstore = 56; | |
| 178 | + int opc_dstore = 57; | |
| 179 | + int opc_astore = 58; | |
| 180 | + int opc_istore_0 = 59; | |
| 181 | + int opc_istore_1 = 60; | |
| 182 | + int opc_istore_2 = 61; | |
| 183 | + int opc_istore_3 = 62; | |
| 184 | + int opc_lstore_0 = 63; | |
| 185 | + int opc_lstore_1 = 64; | |
| 186 | + int opc_lstore_2 = 65; | |
| 187 | + int opc_lstore_3 = 66; | |
| 188 | + int opc_fstore_0 = 67; | |
| 189 | + int opc_fstore_1 = 68; | |
| 190 | + int opc_fstore_2 = 69; | |
| 191 | + int opc_fstore_3 = 70; | |
| 192 | + int opc_dstore_0 = 71; | |
| 193 | + int opc_dstore_1 = 72; | |
| 194 | + int opc_dstore_2 = 73; | |
| 195 | + int opc_dstore_3 = 74; | |
| 196 | + int opc_astore_0 = 75; | |
| 197 | + int opc_astore_1 = 76; | |
| 198 | + int opc_astore_2 = 77; | |
| 199 | + int opc_astore_3 = 78; | |
| 200 | + int opc_iastore = 79; | |
| 201 | + int opc_lastore = 80; | |
| 202 | + int opc_fastore = 81; | |
| 203 | + int opc_dastore = 82; | |
| 204 | + int opc_aastore = 83; | |
| 205 | + int opc_bastore = 84; | |
| 206 | + int opc_castore = 85; | |
| 207 | + int opc_sastore = 86; | |
| 208 | + int opc_pop = 87; | |
| 209 | + int opc_pop2 = 88; | |
| 210 | + int opc_dup = 89; | |
| 211 | + int opc_dup_x1 = 90; | |
| 212 | + int opc_dup_x2 = 91; | |
| 213 | + int opc_dup2 = 92; | |
| 214 | + int opc_dup2_x1 = 93; | |
| 215 | + int opc_dup2_x2 = 94; | |
| 216 | + int opc_swap = 95; | |
| 217 | + int opc_iadd = 96; | |
| 218 | + int opc_ladd = 97; | |
| 219 | + int opc_fadd = 98; | |
| 220 | + int opc_dadd = 99; | |
| 221 | + int opc_isub = 100; | |
| 222 | + int opc_lsub = 101; | |
| 223 | + int opc_fsub = 102; | |
| 224 | + int opc_dsub = 103; | |
| 225 | + int opc_imul = 104; | |
| 226 | + int opc_lmul = 105; | |
| 227 | + int opc_fmul = 106; | |
| 228 | + int opc_dmul = 107; | |
| 229 | + int opc_idiv = 108; | |
| 230 | + int opc_ldiv = 109; | |
| 231 | + int opc_fdiv = 110; | |
| 232 | + int opc_ddiv = 111; | |
| 233 | + int opc_irem = 112; | |
| 234 | + int opc_lrem = 113; | |
| 235 | + int opc_frem = 114; | |
| 236 | + int opc_drem = 115; | |
| 237 | + int opc_ineg = 116; | |
| 238 | + int opc_lneg = 117; | |
| 239 | + int opc_fneg = 118; | |
| 240 | + int opc_dneg = 119; | |
| 241 | + int opc_ishl = 120; | |
| 242 | + int opc_lshl = 121; | |
| 243 | + int opc_ishr = 122; | |
| 244 | + int opc_lshr = 123; | |
| 245 | + int opc_iushr = 124; | |
| 246 | + int opc_lushr = 125; | |
| 247 | + int opc_iand = 126; | |
| 248 | + int opc_land = 127; | |
| 249 | + int opc_ior = 128; | |
| 250 | + int opc_lor = 129; | |
| 251 | + int opc_ixor = 130; | |
| 252 | + int opc_lxor = 131; | |
| 253 | + int opc_iinc = 132; | |
| 254 | + int opc_i2l = 133; | |
| 255 | + int opc_i2f = 134; | |
| 256 | + int opc_i2d = 135; | |
| 257 | + int opc_l2i = 136; | |
| 258 | + int opc_l2f = 137; | |
| 259 | + int opc_l2d = 138; | |
| 260 | + int opc_f2i = 139; | |
| 261 | + int opc_f2l = 140; | |
| 262 | + int opc_f2d = 141; | |
| 263 | + int opc_d2i = 142; | |
| 264 | + int opc_d2l = 143; | |
| 265 | + int opc_d2f = 144; | |
| 266 | + int opc_i2b = 145; | |
| 267 | + int opc_i2c = 146; | |
| 268 | + int opc_i2s = 147; | |
| 269 | + int opc_lcmp = 148; | |
| 270 | + int opc_fcmpl = 149; | |
| 271 | + int opc_fcmpg = 150; | |
| 272 | + int opc_dcmpl = 151; | |
| 273 | + int opc_dcmpg = 152; | |
| 274 | + int opc_ifeq = 153; | |
| 275 | + int opc_ifne = 154; | |
| 276 | + int opc_iflt = 155; | |
| 277 | + int opc_ifge = 156; | |
| 278 | + int opc_ifgt = 157; | |
| 279 | + int opc_ifle = 158; | |
| 280 | + int opc_if_icmpeq = 159; | |
| 281 | + int opc_if_icmpne = 160; | |
| 282 | + int opc_if_icmplt = 161; | |
| 283 | + int opc_if_icmpge = 162; | |
| 284 | + int opc_if_icmpgt = 163; | |
| 285 | + int opc_if_icmple = 164; | |
| 286 | + int opc_if_acmpeq = 165; | |
| 287 | + int opc_if_acmpne = 166; | |
| 288 | + int opc_goto = 167; | |
| 289 | + int opc_jsr = 168; | |
| 290 | + int opc_ret = 169; | |
| 291 | + int opc_tableswitch = 170; | |
| 292 | + int opc_lookupswitch = 171; | |
| 293 | + int opc_ireturn = 172; | |
| 294 | + int opc_lreturn = 173; | |
| 295 | + int opc_freturn = 174; | |
| 296 | + int opc_dreturn = 175; | |
| 297 | + int opc_areturn = 176; | |
| 298 | + int opc_return = 177; | |
| 299 | + int opc_getstatic = 178; | |
| 300 | + int opc_putstatic = 179; | |
| 301 | + int opc_getfield = 180; | |
| 302 | + int opc_putfield = 181; | |
| 303 | + int opc_invokevirtual = 182; | |
| 304 | + int opc_invokespecial = 183; | |
| 305 | + int opc_invokestatic = 184; | |
| 306 | + int opc_invokeinterface = 185; | |
| 307 | + int opc_invokedynamic = 186; | |
| 308 | + int opc_new = 187; | |
| 309 | + int opc_newarray = 188; | |
| 310 | + int opc_anewarray = 189; | |
| 311 | + int opc_arraylength = 190; | |
| 312 | + int opc_athrow = 191; | |
| 313 | + int opc_checkcast = 192; | |
| 314 | + int opc_instanceof = 193; | |
| 315 | + int opc_monitorenter = 194; | |
| 316 | + int opc_monitorexit = 195; | |
| 317 | + int opc_wide = 196; | |
| 318 | + int opc_multianewarray = 197; | |
| 319 | + int opc_ifnull = 198; | |
| 320 | + int opc_ifnonnull = 199; | |
| 321 | + int opc_goto_w = 200; | |
| 322 | + int opc_jsr_w = 201; | |
| 323 | + int opc_breakpoint = 202; | |
| 324 | + | |
| 325 | + /* Opcode Names */ | |
| 326 | + String opcNames[] = { | |
| 327 | + "nop", | |
| 328 | + "aconst_null", | |
| 329 | + "iconst_m1", | |
| 330 | + "iconst_0", | |
| 331 | + "iconst_1", | |
| 332 | + "iconst_2", | |
| 333 | + "iconst_3", | |
| 334 | + "iconst_4", | |
| 335 | + "iconst_5", | |
| 336 | + "lconst_0", | |
| 337 | + "lconst_1", | |
| 338 | + "fconst_0", | |
| 339 | + "fconst_1", | |
| 340 | + "fconst_2", | |
| 341 | + "dconst_0", | |
| 342 | + "dconst_1", | |
| 343 | + "bipush", | |
| 344 | + "sipush", | |
| 345 | + "ldc", | |
| 346 | + "ldc_w", | |
| 347 | + "ldc2_w", | |
| 348 | + "iload", | |
| 349 | + "lload", | |
| 350 | + "fload", | |
| 351 | + "dload", | |
| 352 | + "aload", | |
| 353 | + "iload_0", | |
| 354 | + "iload_1", | |
| 355 | + "iload_2", | |
| 356 | + "iload_3", | |
| 357 | + "lload_0", | |
| 358 | + "lload_1", | |
| 359 | + "lload_2", | |
| 360 | + "lload_3", | |
| 361 | + "fload_0", | |
| 362 | + "fload_1", | |
| 363 | + "fload_2", | |
| 364 | + "fload_3", | |
| 365 | + "dload_0", | |
| 366 | + "dload_1", | |
| 367 | + "dload_2", | |
| 368 | + "dload_3", | |
| 369 | + "aload_0", | |
| 370 | + "aload_1", | |
| 371 | + "aload_2", | |
| 372 | + "aload_3", | |
| 373 | + "iaload", | |
| 374 | + "laload", | |
| 375 | + "faload", | |
| 376 | + "daload", | |
| 377 | + "aaload", | |
| 378 | + "baload", | |
| 379 | + "caload", | |
| 380 | + "saload", | |
| 381 | + "istore", | |
| 382 | + "lstore", | |
| 383 | + "fstore", | |
| 384 | + "dstore", | |
| 385 | + "astore", | |
| 386 | + "istore_0", | |
| 387 | + "istore_1", | |
| 388 | + "istore_2", | |
| 389 | + "istore_3", | |
| 390 | + "lstore_0", | |
| 391 | + "lstore_1", | |
| 392 | + "lstore_2", | |
| 393 | + "lstore_3", | |
| 394 | + "fstore_0", | |
| 395 | + "fstore_1", | |
| 396 | + "fstore_2", | |
| 397 | + "fstore_3", | |
| 398 | + "dstore_0", | |
| 399 | + "dstore_1", | |
| 400 | + "dstore_2", | |
| 401 | + "dstore_3", | |
| 402 | + "astore_0", | |
| 403 | + "astore_1", | |
| 404 | + "astore_2", | |
| 405 | + "astore_3", | |
| 406 | + "iastore", | |
| 407 | + "lastore", | |
| 408 | + "fastore", | |
| 409 | + "dastore", | |
| 410 | + "aastore", | |
| 411 | + "bastore", | |
| 412 | + "castore", | |
| 413 | + "sastore", | |
| 414 | + "pop", | |
| 415 | + "pop2", | |
| 416 | + "dup", | |
| 417 | + "dup_x1", | |
| 418 | + "dup_x2", | |
| 419 | + "dup2", | |
| 420 | + "dup2_x1", | |
| 421 | + "dup2_x2", | |
| 422 | + "swap", | |
| 423 | + "iadd", | |
| 424 | + "ladd", | |
| 425 | + "fadd", | |
| 426 | + "dadd", | |
| 427 | + "isub", | |
| 428 | + "lsub", | |
| 429 | + "fsub", | |
| 430 | + "dsub", | |
| 431 | + "imul", | |
| 432 | + "lmul", | |
| 433 | + "fmul", | |
| 434 | + "dmul", | |
| 435 | + "idiv", | |
| 436 | + "ldiv", | |
| 437 | + "fdiv", | |
| 438 | + "ddiv", | |
| 439 | + "irem", | |
| 440 | + "lrem", | |
| 441 | + "frem", | |
| 442 | + "drem", | |
| 443 | + "ineg", | |
| 444 | + "lneg", | |
| 445 | + "fneg", | |
| 446 | + "dneg", | |
| 447 | + "ishl", | |
| 448 | + "lshl", | |
| 449 | + "ishr", | |
| 450 | + "lshr", | |
| 451 | + "iushr", | |
| 452 | + "lushr", | |
| 453 | + "iand", | |
| 454 | + "land", | |
| 455 | + "ior", | |
| 456 | + "lor", | |
| 457 | + "ixor", | |
| 458 | + "lxor", | |
| 459 | + "iinc", | |
| 460 | + "i2l", | |
| 461 | + "i2f", | |
| 462 | + "i2d", | |
| 463 | + "l2i", | |
| 464 | + "l2f", | |
| 465 | + "l2d", | |
| 466 | + "f2i", | |
| 467 | + "f2l", | |
| 468 | + "f2d", | |
| 469 | + "d2i", | |
| 470 | + "d2l", | |
| 471 | + "d2f", | |
| 472 | + "i2b", | |
| 473 | + "i2c", | |
| 474 | + "i2s", | |
| 475 | + "lcmp", | |
| 476 | + "fcmpl", | |
| 477 | + "fcmpg", | |
| 478 | + "dcmpl", | |
| 479 | + "dcmpg", | |
| 480 | + "ifeq", | |
| 481 | + "ifne", | |
| 482 | + "iflt", | |
| 483 | + "ifge", | |
| 484 | + "ifgt", | |
| 485 | + "ifle", | |
| 486 | + "if_icmpeq", | |
| 487 | + "if_icmpne", | |
| 488 | + "if_icmplt", | |
| 489 | + "if_icmpge", | |
| 490 | + "if_icmpgt", | |
| 491 | + "if_icmple", | |
| 492 | + "if_acmpeq", | |
| 493 | + "if_acmpne", | |
| 494 | + "goto", | |
| 495 | + "jsr", | |
| 496 | + "ret", | |
| 497 | + "tableswitch", | |
| 498 | + "lookupswitch", | |
| 499 | + "ireturn", | |
| 500 | + "lreturn", | |
| 501 | + "freturn", | |
| 502 | + "dreturn", | |
| 503 | + "areturn", | |
| 504 | + "return", | |
| 505 | + "getstatic", | |
| 506 | + "putstatic", | |
| 507 | + "getfield", | |
| 508 | + "putfield", | |
| 509 | + "invokevirtual", | |
| 510 | + "invokespecial", | |
| 511 | + "invokestatic", | |
| 512 | + "invokeinterface", | |
| 513 | + "invokedynamic", | |
| 514 | + "new", | |
| 515 | + "newarray", | |
| 516 | + "anewarray", | |
| 517 | + "arraylength", | |
| 518 | + "athrow", | |
| 519 | + "checkcast", | |
| 520 | + "instanceof", | |
| 521 | + "monitorenter", | |
| 522 | + "monitorexit", | |
| 523 | + "wide", | |
| 524 | + "multianewarray", | |
| 525 | + "ifnull", | |
| 526 | + "ifnonnull", | |
| 527 | + "goto_w", | |
| 528 | + "jsr_w", | |
| 529 | + "breakpoint" | |
| 530 | + }; | |
| 531 | + | |
| 532 | + /* Opcode Lengths */ | |
| 533 | + int opcLengths[] = { | |
| 534 | + 1, | |
| 535 | + 1, | |
| 536 | + 1, | |
| 537 | + 1, | |
| 538 | + 1, | |
| 539 | + 1, | |
| 540 | + 1, | |
| 541 | + 1, | |
| 542 | + 1, | |
| 543 | + 1, | |
| 544 | + 1, | |
| 545 | + 1, | |
| 546 | + 1, | |
| 547 | + 1, | |
| 548 | + 1, | |
| 549 | + 1, | |
| 550 | + 2, | |
| 551 | + 3, | |
| 552 | + 2, | |
| 553 | + 3, | |
| 554 | + 3, | |
| 555 | + 2, | |
| 556 | + 2, | |
| 557 | + 2, | |
| 558 | + 2, | |
| 559 | + 2, | |
| 560 | + 1, | |
| 561 | + 1, | |
| 562 | + 1, | |
| 563 | + 1, | |
| 564 | + 1, | |
| 565 | + 1, | |
| 566 | + 1, | |
| 567 | + 1, | |
| 568 | + 1, | |
| 569 | + 1, | |
| 570 | + 1, | |
| 571 | + 1, | |
| 572 | + 1, | |
| 573 | + 1, | |
| 574 | + 1, | |
| 575 | + 1, | |
| 576 | + 1, | |
| 577 | + 1, | |
| 578 | + 1, | |
| 579 | + 1, | |
| 580 | + 1, | |
| 581 | + 1, | |
| 582 | + 1, | |
| 583 | + 1, | |
| 584 | + 1, | |
| 585 | + 1, | |
| 586 | + 1, | |
| 587 | + 1, | |
| 588 | + 2, | |
| 589 | + 2, | |
| 590 | + 2, | |
| 591 | + 2, | |
| 592 | + 2, | |
| 593 | + 1, | |
| 594 | + 1, | |
| 595 | + 1, | |
| 596 | + 1, | |
| 597 | + 1, | |
| 598 | + 1, | |
| 599 | + 1, | |
| 600 | + 1, | |
| 601 | + 1, | |
| 602 | + 1, | |
| 603 | + 1, | |
| 604 | + 1, | |
| 605 | + 1, | |
| 606 | + 1, | |
| 607 | + 1, | |
| 608 | + 1, | |
| 609 | + 1, | |
| 610 | + 1, | |
| 611 | + 1, | |
| 612 | + 1, | |
| 613 | + 1, | |
| 614 | + 1, | |
| 615 | + 1, | |
| 616 | + 1, | |
| 617 | + 1, | |
| 618 | + 1, | |
| 619 | + 1, | |
| 620 | + 1, | |
| 621 | + 1, | |
| 622 | + 1, | |
| 623 | + 1, | |
| 624 | + 1, | |
| 625 | + 1, | |
| 626 | + 1, | |
| 627 | + 1, | |
| 628 | + 1, | |
| 629 | + 1, | |
| 630 | + 1, | |
| 631 | + 1, | |
| 632 | + 1, | |
| 633 | + 1, | |
| 634 | + 1, | |
| 635 | + 1, | |
| 636 | + 1, | |
| 637 | + 1, | |
| 638 | + 1, | |
| 639 | + 1, | |
| 640 | + 1, | |
| 641 | + 1, | |
| 642 | + 1, | |
| 643 | + 1, | |
| 644 | + 1, | |
| 645 | + 1, | |
| 646 | + 1, | |
| 647 | + 1, | |
| 648 | + 1, | |
| 649 | + 1, | |
| 650 | + 1, | |
| 651 | + 1, | |
| 652 | + 1, | |
| 653 | + 1, | |
| 654 | + 1, | |
| 655 | + 1, | |
| 656 | + 1, | |
| 657 | + 1, | |
| 658 | + 1, | |
| 659 | + 1, | |
| 660 | + 1, | |
| 661 | + 1, | |
| 662 | + 1, | |
| 663 | + 1, | |
| 664 | + 1, | |
| 665 | + 1, | |
| 666 | + 3, | |
| 667 | + 1, | |
| 668 | + 1, | |
| 669 | + 1, | |
| 670 | + 1, | |
| 671 | + 1, | |
| 672 | + 1, | |
| 673 | + 1, | |
| 674 | + 1, | |
| 675 | + 1, | |
| 676 | + 1, | |
| 677 | + 1, | |
| 678 | + 1, | |
| 679 | + 1, | |
| 680 | + 1, | |
| 681 | + 1, | |
| 682 | + 1, | |
| 683 | + 1, | |
| 684 | + 1, | |
| 685 | + 1, | |
| 686 | + 1, | |
| 687 | + 3, | |
| 688 | + 3, | |
| 689 | + 3, | |
| 690 | + 3, | |
| 691 | + 3, | |
| 692 | + 3, | |
| 693 | + 3, | |
| 694 | + 3, | |
| 695 | + 3, | |
| 696 | + 3, | |
| 697 | + 3, | |
| 698 | + 3, | |
| 699 | + 3, | |
| 700 | + 3, | |
| 701 | + 3, | |
| 702 | + 3, | |
| 703 | + 2, | |
| 704 | + 99, | |
| 705 | + 99, | |
| 706 | + 1, | |
| 707 | + 1, | |
| 708 | + 1, | |
| 709 | + 1, | |
| 710 | + 1, | |
| 711 | + 1, | |
| 712 | + 3, | |
| 713 | + 3, | |
| 714 | + 3, | |
| 715 | + 3, | |
| 716 | + 3, | |
| 717 | + 3, | |
| 718 | + 3, | |
| 719 | + 5, | |
| 720 | + 5, | |
| 721 | + 3, | |
| 722 | + 2, | |
| 723 | + 3, | |
| 724 | + 1, | |
| 725 | + 1, | |
| 726 | + 3, | |
| 727 | + 3, | |
| 728 | + 1, | |
| 729 | + 1, | |
| 730 | + 0, | |
| 731 | + 4, | |
| 732 | + 3, | |
| 733 | + 3, | |
| 734 | + 5, | |
| 735 | + 5, | |
| 736 | + 1 | |
| 737 | + }; | |
| 738 | + | |
| 739 | +} | |
| @@ -0,0 +1,1341 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +import java.io.IOException; | |
| 29 | +import java.io.InputStream; | |
| 30 | +import java.util.Hashtable; | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * A Scanner for Java tokens. Errors are reported | |
| 34 | + * to the environment object.<p> | |
| 35 | + * | |
| 36 | + * The scanner keeps track of the current token, | |
| 37 | + * the value of the current token (if any), and the start | |
| 38 | + * position of the current token.<p> | |
| 39 | + * | |
| 40 | + * The scan() method advances the scanner to the next | |
| 41 | + * token in the input.<p> | |
| 42 | + * | |
| 43 | + * The match() method is used to quickly match opening | |
| 44 | + * brackets (ie: '(', '{', or '[') with their closing | |
| 45 | + * counter part. This is useful during error recovery.<p> | |
| 46 | + * | |
| 47 | + * An position consists of: ((linenr << WHEREOFFSETBITS) | offset) | |
| 48 | + * this means that both the line number and the exact offset into | |
| 49 | + * the file are encoded in each position value.<p> | |
| 50 | + * | |
| 51 | + * The compiler treats either "\n", "\r" or "\r\n" as the | |
| 52 | + * end of a line.<p> | |
| 53 | + * | |
| 54 | + * WARNING: The contents of this source file are not part of any | |
| 55 | + * supported API. Code that depends on them does so at its own risk: | |
| 56 | + * they are subject to change or removal without notice. | |
| 57 | + * | |
| 58 | + * @author Arthur van Hoff | |
| 59 | + */ | |
| 60 | + | |
| 61 | +public | |
| 62 | +class Scanner implements Constants { | |
| 63 | + /** | |
| 64 | + * The increment for each character. | |
| 65 | + */ | |
| 66 | + public static final long OFFSETINC = 1; | |
| 67 | + | |
| 68 | + /** | |
| 69 | + * The increment for each line. | |
| 70 | + */ | |
| 71 | + public static final long LINEINC = 1L << WHEREOFFSETBITS; | |
| 72 | + | |
| 73 | + /** | |
| 74 | + * End of input | |
| 75 | + */ | |
| 76 | + public static final int EOF = -1; | |
| 77 | + | |
| 78 | + /** | |
| 79 | + * Where errors are reported | |
| 80 | + */ | |
| 81 | + public Environment env; | |
| 82 | + | |
| 83 | + /** | |
| 84 | + * Input reader | |
| 85 | + */ | |
| 86 | + protected ScannerInputReader in; | |
| 87 | + | |
| 88 | + /** | |
| 89 | + * If true, present all comments as tokens. | |
| 90 | + * Contents are not saved, but positions are recorded accurately, | |
| 91 | + * so the comment can be recovered from the text. | |
| 92 | + * Line terminations are also returned as comment tokens, | |
| 93 | + * and may be distinguished by their start and end positions, | |
| 94 | + * which are equal (meaning, these tokens contain no chars). | |
| 95 | + */ | |
| 96 | + public boolean scanComments = false; | |
| 97 | + | |
| 98 | + /** | |
| 99 | + * Current token | |
| 100 | + */ | |
| 101 | + public int token; | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * The position of the current token | |
| 105 | + */ | |
| 106 | + public long pos; | |
| 107 | + | |
| 108 | + /** | |
| 109 | + * The position of the previous token | |
| 110 | + */ | |
| 111 | + public long prevPos; | |
| 112 | + | |
| 113 | + /** | |
| 114 | + * The current character | |
| 115 | + */ | |
| 116 | + protected int ch; | |
| 117 | + | |
| 118 | + /* | |
| 119 | + * Token values. | |
| 120 | + */ | |
| 121 | + public char charValue; | |
| 122 | + public int intValue; | |
| 123 | + public long longValue; | |
| 124 | + public float floatValue; | |
| 125 | + public double doubleValue; | |
| 126 | + public String stringValue; | |
| 127 | + public Identifier idValue; | |
| 128 | + public int radix; // Radix, when reading int or long | |
| 129 | + | |
| 130 | + /* | |
| 131 | + * A doc comment preceding the most recent token | |
| 132 | + */ | |
| 133 | + public String docComment; | |
| 134 | + | |
| 135 | + /* | |
| 136 | + * A growable character buffer. | |
| 137 | + */ | |
| 138 | + private int count; | |
| 139 | + private char buffer[] = new char[1024]; | |
| 140 | + private void growBuffer() { | |
| 141 | + char newBuffer[] = new char[buffer.length * 2]; | |
| 142 | + System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); | |
| 143 | + buffer = newBuffer; | |
| 144 | + } | |
| 145 | + | |
| 146 | + // The following two methods have been hand-inlined in | |
| 147 | + // scanDocComment. If you make changes here, you should | |
| 148 | + // check to see if scanDocComment also needs modification. | |
| 149 | + private void putc(int ch) { | |
| 150 | + if (count == buffer.length) { | |
| 151 | + growBuffer(); | |
| 152 | + } | |
| 153 | + buffer[count++] = (char)ch; | |
| 154 | + } | |
| 155 | + | |
| 156 | + private String bufferString() { | |
| 157 | + return new String(buffer, 0, count); | |
| 158 | + } | |
| 159 | + | |
| 160 | + /** | |
| 161 | + * Create a scanner to scan an input stream. | |
| 162 | + */ | |
| 163 | + public Scanner(Environment env, InputStream in) throws IOException { | |
| 164 | + this.env = env; | |
| 165 | + useInputStream(in); | |
| 166 | + } | |
| 167 | + | |
| 168 | + /** | |
| 169 | + * Setup input from the given input stream, | |
| 170 | + * and scan the first token from it. | |
| 171 | + */ | |
| 172 | + protected void useInputStream(InputStream in) throws IOException { | |
| 173 | + try { | |
| 174 | + this.in = new ScannerInputReader(env, in); | |
| 175 | + } catch (Exception e) { | |
| 176 | + env.setCharacterEncoding(null); | |
| 177 | + this.in = new ScannerInputReader(env, in); | |
| 178 | + } | |
| 179 | + | |
| 180 | + ch = this.in.read(); | |
| 181 | + prevPos = this.in.pos; | |
| 182 | + | |
| 183 | + scan(); | |
| 184 | + } | |
| 185 | + | |
| 186 | + /** | |
| 187 | + * Create a scanner to scan an input stream. | |
| 188 | + */ | |
| 189 | + protected Scanner(Environment env) { | |
| 190 | + this.env = env; | |
| 191 | + // Expect the subclass to call useInputStream at the right time. | |
| 192 | + } | |
| 193 | + | |
| 194 | + /** | |
| 195 | + * Define a keyword. | |
| 196 | + */ | |
| 197 | + private static void defineKeyword(int val) { | |
| 198 | + Identifier.lookup(opNames[val]).setType(val); | |
| 199 | + } | |
| 200 | + | |
| 201 | + /** | |
| 202 | + * Initialized keyword and token Hashtables | |
| 203 | + */ | |
| 204 | + static { | |
| 205 | + // Statement keywords | |
| 206 | + defineKeyword(FOR); | |
| 207 | + defineKeyword(IF); | |
| 208 | + defineKeyword(ELSE); | |
| 209 | + defineKeyword(WHILE); | |
| 210 | + defineKeyword(DO); | |
| 211 | + defineKeyword(SWITCH); | |
| 212 | + defineKeyword(CASE); | |
| 213 | + defineKeyword(DEFAULT); | |
| 214 | + defineKeyword(BREAK); | |
| 215 | + defineKeyword(CONTINUE); | |
| 216 | + defineKeyword(RETURN); | |
| 217 | + defineKeyword(TRY); | |
| 218 | + defineKeyword(CATCH); | |
| 219 | + defineKeyword(FINALLY); | |
| 220 | + defineKeyword(THROW); | |
| 221 | + | |
| 222 | + // Type defineKeywords | |
| 223 | + defineKeyword(BYTE); | |
| 224 | + defineKeyword(CHAR); | |
| 225 | + defineKeyword(SHORT); | |
| 226 | + defineKeyword(INT); | |
| 227 | + defineKeyword(LONG); | |
| 228 | + defineKeyword(FLOAT); | |
| 229 | + defineKeyword(DOUBLE); | |
| 230 | + defineKeyword(VOID); | |
| 231 | + defineKeyword(BOOLEAN); | |
| 232 | + | |
| 233 | + // Expression keywords | |
| 234 | + defineKeyword(INSTANCEOF); | |
| 235 | + defineKeyword(TRUE); | |
| 236 | + defineKeyword(FALSE); | |
| 237 | + defineKeyword(NEW); | |
| 238 | + defineKeyword(THIS); | |
| 239 | + defineKeyword(SUPER); | |
| 240 | + defineKeyword(NULL); | |
| 241 | + | |
| 242 | + // Declaration keywords | |
| 243 | + defineKeyword(IMPORT); | |
| 244 | + defineKeyword(CLASS); | |
| 245 | + defineKeyword(EXTENDS); | |
| 246 | + defineKeyword(IMPLEMENTS); | |
| 247 | + defineKeyword(INTERFACE); | |
| 248 | + defineKeyword(PACKAGE); | |
| 249 | + defineKeyword(THROWS); | |
| 250 | + | |
| 251 | + // Modifier keywords | |
| 252 | + defineKeyword(PRIVATE); | |
| 253 | + defineKeyword(PUBLIC); | |
| 254 | + defineKeyword(PROTECTED); | |
| 255 | + defineKeyword(STATIC); | |
| 256 | + defineKeyword(TRANSIENT); | |
| 257 | + defineKeyword(SYNCHRONIZED); | |
| 258 | + defineKeyword(NATIVE); | |
| 259 | + defineKeyword(ABSTRACT); | |
| 260 | + defineKeyword(VOLATILE); | |
| 261 | + defineKeyword(FINAL); | |
| 262 | + defineKeyword(STRICTFP); | |
| 263 | + | |
| 264 | + // reserved keywords | |
| 265 | + defineKeyword(CONST); | |
| 266 | + defineKeyword(GOTO); | |
| 267 | + } | |
| 268 | + | |
| 269 | + /** | |
| 270 | + * Scan a comment. This method should be | |
| 271 | + * called once the initial /, * and the next | |
| 272 | + * character have been read. | |
| 273 | + */ | |
| 274 | + private void skipComment() throws IOException { | |
| 275 | + while (true) { | |
| 276 | + switch (ch) { | |
| 277 | + case EOF: | |
| 278 | + env.error(pos, "eof.in.comment"); | |
| 279 | + return; | |
| 280 | + | |
| 281 | + case '*': | |
| 282 | + if ((ch = in.read()) == '/') { | |
| 283 | + ch = in.read(); | |
| 284 | + return; | |
| 285 | + } | |
| 286 | + break; | |
| 287 | + | |
| 288 | + default: | |
| 289 | + ch = in.read(); | |
| 290 | + break; | |
| 291 | + } | |
| 292 | + } | |
| 293 | + } | |
| 294 | + | |
| 295 | + /** | |
| 296 | + * Scan a doc comment. This method should be called | |
| 297 | + * once the initial /, * and * have been read. It gathers | |
| 298 | + * the content of the comment (witout leading spaces and '*'s) | |
| 299 | + * in the string buffer. | |
| 300 | + */ | |
| 301 | + private String scanDocComment() throws IOException { | |
| 302 | + // Note: this method has been hand-optimized to yield | |
| 303 | + // better performance. This was done after it was noted | |
| 304 | + // that javadoc spent a great deal of its time here. | |
| 305 | + // This should also help the performance of the compiler | |
| 306 | + // as well -- it scans the doc comments to find | |
| 307 | + // @deprecated tags. | |
| 308 | + // | |
| 309 | + // The logic of the method has been completely rewritten | |
| 310 | + // to avoid the use of flags that need to be looked at | |
| 311 | + // for every character read. Members that are accessed | |
| 312 | + // more than once have been stored in local variables. | |
| 313 | + // The methods putc() and bufferString() have been | |
| 314 | + // inlined by hand. Extra cases have been added to | |
| 315 | + // switch statements to trick the compiler into generating | |
| 316 | + // a tableswitch instead of a lookupswitch. | |
| 317 | + // | |
| 318 | + // This implementation aims to preserve the previous | |
| 319 | + // behavior of this method. | |
| 320 | + | |
| 321 | + int c; | |
| 322 | + | |
| 323 | + // Put `in' in a local variable. | |
| 324 | + final ScannerInputReader in = this.in; | |
| 325 | + | |
| 326 | + // We maintain the buffer locally rather than calling putc(). | |
| 327 | + char[] buffer = this.buffer; | |
| 328 | + int count = 0; | |
| 329 | + | |
| 330 | + // We are called pointing at the second star of the doc | |
| 331 | + // comment: | |
| 332 | + // | |
| 333 | + // Input: /** the rest of the comment ... */ | |
| 334 | + // ^ | |
| 335 | + // | |
| 336 | + // We rely on this in the code below. | |
| 337 | + | |
| 338 | + // Consume any number of stars. | |
| 339 | + while ((c = in.read()) == '*') | |
| 340 | + ; | |
| 341 | + | |
| 342 | + // Is the comment of the form /**/, /***/, /****/, etc.? | |
| 343 | + if (c == '/') { | |
| 344 | + // Set ch and return | |
| 345 | + ch = in.read(); | |
| 346 | + return ""; | |
| 347 | + } | |
| 348 | + | |
| 349 | + // Skip a newline on the first line of the comment. | |
| 350 | + if (c == '\n') { | |
| 351 | + c = in.read(); | |
| 352 | + } | |
| 353 | + | |
| 354 | + outerLoop: | |
| 355 | + // The outerLoop processes the doc comment, looping once | |
| 356 | + // for each line. For each line, it first strips off | |
| 357 | + // whitespace, then it consumes any stars, then it | |
| 358 | + // puts the rest of the line into our buffer. | |
| 359 | + while (true) { | |
| 360 | + | |
| 361 | + // The wsLoop consumes whitespace from the beginning | |
| 362 | + // of each line. | |
| 363 | + wsLoop: | |
| 364 | + while (true) { | |
| 365 | + switch (c) { | |
| 366 | + case ' ': | |
| 367 | + case '\t': | |
| 368 | + // We could check for other forms of whitespace | |
| 369 | + // as well, but this is left as is for minimum | |
| 370 | + // disturbance of functionality. | |
| 371 | + // | |
| 372 | + // Just skip whitespace. | |
| 373 | + c = in.read(); | |
| 374 | + break; | |
| 375 | + | |
| 376 | + // We have added extra cases here to trick the | |
| 377 | + // compiler into using a tableswitch instead of | |
| 378 | + // a lookupswitch. They can be removed without | |
| 379 | + // a change in meaning. | |
| 380 | + case 10: case 11: case 12: case 13: case 14: case 15: | |
| 381 | + case 16: case 17: case 18: case 19: case 20: case 21: | |
| 382 | + case 22: case 23: case 24: case 25: case 26: case 27: | |
| 383 | + case 28: case 29: case 30: case 31: | |
| 384 | + default: | |
| 385 | + // We've seen something that isn't whitespace, | |
| 386 | + // jump out. | |
| 387 | + break wsLoop; | |
| 388 | + } | |
| 389 | + } // end wsLoop. | |
| 390 | + | |
| 391 | + // Are there stars here? If so, consume them all | |
| 392 | + // and check for the end of comment. | |
| 393 | + if (c == '*') { | |
| 394 | + // Skip all of the stars... | |
| 395 | + do { | |
| 396 | + c = in.read(); | |
| 397 | + } while (c == '*'); | |
| 398 | + | |
| 399 | + // ...then check for the closing slash. | |
| 400 | + if (c == '/') { | |
| 401 | + // We're done with the doc comment. | |
| 402 | + // Set ch and break out. | |
| 403 | + ch = in.read(); | |
| 404 | + break outerLoop; | |
| 405 | + } | |
| 406 | + } | |
| 407 | + | |
| 408 | + // The textLoop processes the rest of the characters | |
| 409 | + // on the line, adding them to our buffer. | |
| 410 | + textLoop: | |
| 411 | + while (true) { | |
| 412 | + switch (c) { | |
| 413 | + case EOF: | |
| 414 | + // We've seen a premature EOF. Break out | |
| 415 | + // of the loop. | |
| 416 | + env.error(pos, "eof.in.comment"); | |
| 417 | + ch = EOF; | |
| 418 | + break outerLoop; | |
| 419 | + | |
| 420 | + case '*': | |
| 421 | + // Is this just a star? Or is this the | |
| 422 | + // end of a comment? | |
| 423 | + c = in.read(); | |
| 424 | + if (c == '/') { | |
| 425 | + // This is the end of the comment, | |
| 426 | + // set ch and return our buffer. | |
| 427 | + ch = in.read(); | |
| 428 | + break outerLoop; | |
| 429 | + } | |
| 430 | + // This is just an ordinary star. Add it to | |
| 431 | + // the buffer. | |
| 432 | + if (count == buffer.length) { | |
| 433 | + growBuffer(); | |
| 434 | + buffer = this.buffer; | |
| 435 | + } | |
| 436 | + buffer[count++] = '*'; | |
| 437 | + break; | |
| 438 | + | |
| 439 | + case '\n': | |
| 440 | + // We've seen a newline. Add it to our | |
| 441 | + // buffer and break out of this loop, | |
| 442 | + // starting fresh on a new line. | |
| 443 | + if (count == buffer.length) { | |
| 444 | + growBuffer(); | |
| 445 | + buffer = this.buffer; | |
| 446 | + } | |
| 447 | + buffer[count++] = '\n'; | |
| 448 | + c = in.read(); | |
| 449 | + break textLoop; | |
| 450 | + | |
| 451 | + // Again, the extra cases here are a trick | |
| 452 | + // to get the compiler to generate a tableswitch. | |
| 453 | + case 0: case 1: case 2: case 3: case 4: case 5: | |
| 454 | + case 6: case 7: case 8: case 11: case 12: case 13: | |
| 455 | + case 14: case 15: case 16: case 17: case 18: case 19: | |
| 456 | + case 20: case 21: case 22: case 23: case 24: case 25: | |
| 457 | + case 26: case 27: case 28: case 29: case 30: case 31: | |
| 458 | + case 32: case 33: case 34: case 35: case 36: case 37: | |
| 459 | + case 38: case 39: case 40: | |
| 460 | + default: | |
| 461 | + // Add the character to our buffer. | |
| 462 | + if (count == buffer.length) { | |
| 463 | + growBuffer(); | |
| 464 | + buffer = this.buffer; | |
| 465 | + } | |
| 466 | + buffer[count++] = (char)c; | |
| 467 | + c = in.read(); | |
| 468 | + break; | |
| 469 | + } | |
| 470 | + } // end textLoop | |
| 471 | + } // end outerLoop | |
| 472 | + | |
| 473 | + // We have scanned our doc comment. It is stored in | |
| 474 | + // buffer. The previous implementation of scanDocComment | |
| 475 | + // stripped off all trailing spaces and stars from the comment. | |
| 476 | + // We will do this as well, so as to cause a minimum of | |
| 477 | + // disturbance. Is this what we want? | |
| 478 | + if (count > 0) { | |
| 479 | + int i = count - 1; | |
| 480 | + trailLoop: | |
| 481 | + while (i > -1) { | |
| 482 | + switch (buffer[i]) { | |
| 483 | + case ' ': | |
| 484 | + case '\t': | |
| 485 | + case '*': | |
| 486 | + i--; | |
| 487 | + break; | |
| 488 | + // And again, the extra cases here are a trick | |
| 489 | + // to get the compiler to generate a tableswitch. | |
| 490 | + case 0: case 1: case 2: case 3: case 4: case 5: | |
| 491 | + case 6: case 7: case 8: case 10: case 11: case 12: | |
| 492 | + case 13: case 14: case 15: case 16: case 17: case 18: | |
| 493 | + case 19: case 20: case 21: case 22: case 23: case 24: | |
| 494 | + case 25: case 26: case 27: case 28: case 29: case 30: | |
| 495 | + case 31: case 33: case 34: case 35: case 36: case 37: | |
| 496 | + case 38: case 39: case 40: | |
| 497 | + default: | |
| 498 | + break trailLoop; | |
| 499 | + } | |
| 500 | + } | |
| 501 | + count = i + 1; | |
| 502 | + | |
| 503 | + // Return the text of the doc comment. | |
| 504 | + return new String(buffer, 0, count); | |
| 505 | + } else { | |
| 506 | + return ""; | |
| 507 | + } | |
| 508 | + } | |
| 509 | + | |
| 510 | + /** | |
| 511 | + * Scan a number. The first digit of the number should be the current | |
| 512 | + * character. We may be scanning hex, decimal, or octal at this point | |
| 513 | + */ | |
| 514 | + private void scanNumber() throws IOException { | |
| 515 | + boolean seenNonOctal = false; | |
| 516 | + boolean overflow = false; | |
| 517 | + boolean seenDigit = false; // used to detect invalid hex number 0xL | |
| 518 | + radix = (ch == '0' ? 8 : 10); | |
| 519 | + long value = ch - '0'; | |
| 520 | + count = 0; | |
| 521 | + putc(ch); // save character in buffer | |
| 522 | + numberLoop: | |
| 523 | + for (;;) { | |
| 524 | + switch (ch = in.read()) { | |
| 525 | + case '.': | |
| 526 | + if (radix == 16) | |
| 527 | + break numberLoop; // an illegal character | |
| 528 | + scanReal(); | |
| 529 | + return; | |
| 530 | + | |
| 531 | + case '8': case '9': | |
| 532 | + // We can't yet throw an error if reading an octal. We might | |
| 533 | + // discover we're really reading a real. | |
| 534 | + seenNonOctal = true; | |
| 535 | + case '0': case '1': case '2': case '3': | |
| 536 | + case '4': case '5': case '6': case '7': | |
| 537 | + seenDigit = true; | |
| 538 | + putc(ch); | |
| 539 | + if (radix == 10) { | |
| 540 | + overflow = overflow || (value * 10)/10 != value; | |
| 541 | + value = (value * 10) + (ch - '0'); | |
| 542 | + overflow = overflow || (value - 1 < -1); | |
| 543 | + } else if (radix == 8) { | |
| 544 | + overflow = overflow || (value >>> 61) != 0; | |
| 545 | + value = (value << 3) + (ch - '0'); | |
| 546 | + } else { | |
| 547 | + overflow = overflow || (value >>> 60) != 0; | |
| 548 | + value = (value << 4) + (ch - '0'); | |
| 549 | + } | |
| 550 | + break; | |
| 551 | + | |
| 552 | + case 'd': case 'D': case 'e': case 'E': case 'f': case 'F': | |
| 553 | + if (radix != 16) { | |
| 554 | + scanReal(); | |
| 555 | + return; | |
| 556 | + } | |
| 557 | + // fall through | |
| 558 | + case 'a': case 'A': case 'b': case 'B': case 'c': case 'C': | |
| 559 | + seenDigit = true; | |
| 560 | + putc(ch); | |
| 561 | + if (radix != 16) | |
| 562 | + break numberLoop; // an illegal character | |
| 563 | + overflow = overflow || (value >>> 60) != 0; | |
| 564 | + value = (value << 4) + 10 + | |
| 565 | + Character.toLowerCase((char)ch) - 'a'; | |
| 566 | + break; | |
| 567 | + | |
| 568 | + case 'l': case 'L': | |
| 569 | + ch = in.read(); // skip over 'l' | |
| 570 | + longValue = value; | |
| 571 | + token = LONGVAL; | |
| 572 | + break numberLoop; | |
| 573 | + | |
| 574 | + case 'x': case 'X': | |
| 575 | + // if the first character is a '0' and this is the second | |
| 576 | + // letter, then read in a hexadecimal number. Otherwise, error. | |
| 577 | + if (count == 1 && radix == 8) { | |
| 578 | + radix = 16; | |
| 579 | + seenDigit = false; | |
| 580 | + break; | |
| 581 | + } else { | |
| 582 | + // we'll get an illegal character error | |
| 583 | + break numberLoop; | |
| 584 | + } | |
| 585 | + | |
| 586 | + default: | |
| 587 | + intValue = (int)value; | |
| 588 | + token = INTVAL; | |
| 589 | + break numberLoop; | |
| 590 | + } | |
| 591 | + } // while true | |
| 592 | + | |
| 593 | + // We have just finished reading the number. The next thing better | |
| 594 | + // not be a letter or digit. | |
| 595 | + // Note: There will be deprecation warnings against these uses | |
| 596 | + // of Character.isJavaLetterOrDigit and Character.isJavaLetter. | |
| 597 | + // Do not fix them yet; allow the compiler to run on pre-JDK1.1 VMs. | |
| 598 | + if (Character.isJavaLetterOrDigit((char)ch) || ch == '.') { | |
| 599 | + env.error(in.pos, "invalid.number"); | |
| 600 | + do { ch = in.read(); } | |
| 601 | + while (Character.isJavaLetterOrDigit((char)ch) || ch == '.'); | |
| 602 | + intValue = 0; | |
| 603 | + token = INTVAL; | |
| 604 | + } else if (radix == 8 && seenNonOctal) { | |
| 605 | + // A bogus octal literal. | |
| 606 | + intValue = 0; | |
| 607 | + token = INTVAL; | |
| 608 | + env.error(pos, "invalid.octal.number"); | |
| 609 | + } else if (radix == 16 && seenDigit == false) { | |
| 610 | + // A hex literal with no digits, 0xL, for example. | |
| 611 | + intValue = 0; | |
| 612 | + token = INTVAL; | |
| 613 | + env.error(pos, "invalid.hex.number"); | |
| 614 | + } else { | |
| 615 | + if (token == INTVAL) { | |
| 616 | + // Check for overflow. Note that base 10 literals | |
| 617 | + // have different rules than base 8 and 16. | |
| 618 | + overflow = overflow || | |
| 619 | + (value & 0xFFFFFFFF00000000L) != 0 || | |
| 620 | + (radix == 10 && value > 2147483648L); | |
| 621 | + | |
| 622 | + if (overflow) { | |
| 623 | + intValue = 0; | |
| 624 | + | |
| 625 | + // Give a specific error message which tells | |
| 626 | + // the user the range. | |
| 627 | + switch (radix) { | |
| 628 | + case 8: | |
| 629 | + env.error(pos, "overflow.int.oct"); | |
| 630 | + break; | |
| 631 | + case 10: | |
| 632 | + env.error(pos, "overflow.int.dec"); | |
| 633 | + break; | |
| 634 | + case 16: | |
| 635 | + env.error(pos, "overflow.int.hex"); | |
| 636 | + break; | |
| 637 | + default: | |
| 638 | + throw new CompilerError("invalid radix"); | |
| 639 | + } | |
| 640 | + } | |
| 641 | + } else { | |
| 642 | + if (overflow) { | |
| 643 | + longValue = 0; | |
| 644 | + | |
| 645 | + // Give a specific error message which tells | |
| 646 | + // the user the range. | |
| 647 | + switch (radix) { | |
| 648 | + case 8: | |
| 649 | + env.error(pos, "overflow.long.oct"); | |
| 650 | + break; | |
| 651 | + case 10: | |
| 652 | + env.error(pos, "overflow.long.dec"); | |
| 653 | + break; | |
| 654 | + case 16: | |
| 655 | + env.error(pos, "overflow.long.hex"); | |
| 656 | + break; | |
| 657 | + default: | |
| 658 | + throw new CompilerError("invalid radix"); | |
| 659 | + } | |
| 660 | + } | |
| 661 | + } | |
| 662 | + } | |
| 663 | + } | |
| 664 | + | |
| 665 | + /** | |
| 666 | + * Scan a float. We are either looking at the decimal, or we have already | |
| 667 | + * seen it and put it into the buffer. We haven't seen an exponent. | |
| 668 | + * Scan a float. Should be called with the current character is either | |
| 669 | + * the 'e', 'E' or '.' | |
| 670 | + */ | |
| 671 | + private void scanReal() throws IOException { | |
| 672 | + boolean seenExponent = false; | |
| 673 | + boolean isSingleFloat = false; | |
| 674 | + char lastChar; | |
| 675 | + if (ch == '.') { | |
| 676 | + putc(ch); | |
| 677 | + ch = in.read(); | |
| 678 | + } | |
| 679 | + | |
| 680 | + numberLoop: | |
| 681 | + for ( ; ; ch = in.read()) { | |
| 682 | + switch (ch) { | |
| 683 | + case '0': case '1': case '2': case '3': case '4': | |
| 684 | + case '5': case '6': case '7': case '8': case '9': | |
| 685 | + putc(ch); | |
| 686 | + break; | |
| 687 | + | |
| 688 | + case 'e': case 'E': | |
| 689 | + if (seenExponent) | |
| 690 | + break numberLoop; // we'll get a format error | |
| 691 | + putc(ch); | |
| 692 | + seenExponent = true; | |
| 693 | + break; | |
| 694 | + | |
| 695 | + case '+': case '-': | |
| 696 | + lastChar = buffer[count - 1]; | |
| 697 | + if (lastChar != 'e' && lastChar != 'E') | |
| 698 | + break numberLoop; // this isn't an error, though! | |
| 699 | + putc(ch); | |
| 700 | + break; | |
| 701 | + | |
| 702 | + case 'f': case 'F': | |
| 703 | + ch = in.read(); // skip over 'f' | |
| 704 | + isSingleFloat = true; | |
| 705 | + break numberLoop; | |
| 706 | + | |
| 707 | + case 'd': case 'D': | |
| 708 | + ch = in.read(); // skip over 'd' | |
| 709 | + // fall through | |
| 710 | + default: | |
| 711 | + break numberLoop; | |
| 712 | + } // sswitch | |
| 713 | + } // loop | |
| 714 | + | |
| 715 | + // we have just finished reading the number. The next thing better | |
| 716 | + // not be a letter or digit. | |
| 717 | + if (Character.isJavaLetterOrDigit((char)ch) || ch == '.') { | |
| 718 | + env.error(in.pos, "invalid.number"); | |
| 719 | + do { ch = in.read(); } | |
| 720 | + while (Character.isJavaLetterOrDigit((char)ch) || ch == '.'); | |
| 721 | + doubleValue = 0; | |
| 722 | + token = DOUBLEVAL; | |
| 723 | + } else { | |
| 724 | + token = isSingleFloat ? FLOATVAL : DOUBLEVAL; | |
| 725 | + try { | |
| 726 | + lastChar = buffer[count - 1]; | |
| 727 | + if (lastChar == 'e' || lastChar == 'E' | |
| 728 | + || lastChar == '+' || lastChar == '-') { | |
| 729 | + env.error(in.pos -1, "float.format"); | |
| 730 | + } else if (isSingleFloat) { | |
| 731 | + String string = bufferString(); | |
| 732 | + floatValue = Float.valueOf(string).floatValue(); | |
| 733 | + if (Float.isInfinite(floatValue)) { | |
| 734 | + env.error(pos, "overflow.float"); | |
| 735 | + } else if (floatValue == 0 && !looksLikeZero(string)) { | |
| 736 | + env.error(pos, "underflow.float"); | |
| 737 | + } | |
| 738 | + } else { | |
| 739 | + String string = bufferString(); | |
| 740 | + doubleValue = Double.valueOf(string).doubleValue(); | |
| 741 | + if (Double.isInfinite(doubleValue)) { | |
| 742 | + env.error(pos, "overflow.double"); | |
| 743 | + } else if (doubleValue == 0 && !looksLikeZero(string)) { | |
| 744 | + env.error(pos, "underflow.double"); | |
| 745 | + } | |
| 746 | + } | |
| 747 | + } catch (NumberFormatException ee) { | |
| 748 | + env.error(pos, "float.format"); | |
| 749 | + doubleValue = 0; | |
| 750 | + floatValue = 0; | |
| 751 | + } | |
| 752 | + } | |
| 753 | + return; | |
| 754 | + } | |
| 755 | + | |
| 756 | + // We have a token that parses as a number. Is this token possibly zero? | |
| 757 | + // i.e. does it have a non-zero value in the mantissa? | |
| 758 | + private static boolean looksLikeZero(String token) { | |
| 759 | + int length = token.length(); | |
| 760 | + for (int i = 0; i < length; i++) { | |
| 761 | + switch (token.charAt(i)) { | |
| 762 | + case 0: case '.': | |
| 763 | + continue; | |
| 764 | + case '1': case '2': case '3': case '4': case '5': | |
| 765 | + case '6': case '7': case '8': case '9': | |
| 766 | + return false; | |
| 767 | + case 'e': case 'E': case 'f': case 'F': | |
| 768 | + return true; | |
| 769 | + } | |
| 770 | + } | |
| 771 | + return true; | |
| 772 | + } | |
| 773 | + | |
| 774 | + /** | |
| 775 | + * Scan an escape character. | |
| 776 | + * @return the character or -1 if it escaped an | |
| 777 | + * end-of-line. | |
| 778 | + */ | |
| 779 | + private int scanEscapeChar() throws IOException { | |
| 780 | + long p = in.pos; | |
| 781 | + | |
| 782 | + switch (ch = in.read()) { | |
| 783 | + case '0': case '1': case '2': case '3': | |
| 784 | + case '4': case '5': case '6': case '7': { | |
| 785 | + int n = ch - '0'; | |
| 786 | + for (int i = 2 ; i > 0 ; i--) { | |
| 787 | + switch (ch = in.read()) { | |
| 788 | + case '0': case '1': case '2': case '3': | |
| 789 | + case '4': case '5': case '6': case '7': | |
| 790 | + n = (n << 3) + ch - '0'; | |
| 791 | + break; | |
| 792 | + | |
| 793 | + default: | |
| 794 | + if (n > 0xFF) { | |
| 795 | + env.error(p, "invalid.escape.char"); | |
| 796 | + } | |
| 797 | + return n; | |
| 798 | + } | |
| 799 | + } | |
| 800 | + ch = in.read(); | |
| 801 | + if (n > 0xFF) { | |
| 802 | + env.error(p, "invalid.escape.char"); | |
| 803 | + } | |
| 804 | + return n; | |
| 805 | + } | |
| 806 | + | |
| 807 | + case 'r': ch = in.read(); return '\r'; | |
| 808 | + case 'n': ch = in.read(); return '\n'; | |
| 809 | + case 'f': ch = in.read(); return '\f'; | |
| 810 | + case 'b': ch = in.read(); return '\b'; | |
| 811 | + case 't': ch = in.read(); return '\t'; | |
| 812 | + case '\\': ch = in.read(); return '\\'; | |
| 813 | + case '\"': ch = in.read(); return '\"'; | |
| 814 | + case '\'': ch = in.read(); return '\''; | |
| 815 | + } | |
| 816 | + | |
| 817 | + env.error(p, "invalid.escape.char"); | |
| 818 | + ch = in.read(); | |
| 819 | + return -1; | |
| 820 | + } | |
| 821 | + | |
| 822 | + /** | |
| 823 | + * Scan a string. The current character | |
| 824 | + * should be the opening " of the string. | |
| 825 | + */ | |
| 826 | + private void scanString() throws IOException { | |
| 827 | + token = STRINGVAL; | |
| 828 | + count = 0; | |
| 829 | + ch = in.read(); | |
| 830 | + | |
| 831 | + // Scan a String | |
| 832 | + while (true) { | |
| 833 | + switch (ch) { | |
| 834 | + case EOF: | |
| 835 | + env.error(pos, "eof.in.string"); | |
| 836 | + stringValue = bufferString(); | |
| 837 | + return; | |
| 838 | + | |
| 839 | + case '\r': | |
| 840 | + case '\n': | |
| 841 | + ch = in.read(); | |
| 842 | + env.error(pos, "newline.in.string"); | |
| 843 | + stringValue = bufferString(); | |
| 844 | + return; | |
| 845 | + | |
| 846 | + case '"': | |
| 847 | + ch = in.read(); | |
| 848 | + stringValue = bufferString(); | |
| 849 | + return; | |
| 850 | + | |
| 851 | + case '\\': { | |
| 852 | + int c = scanEscapeChar(); | |
| 853 | + if (c >= 0) { | |
| 854 | + putc((char)c); | |
| 855 | + } | |
| 856 | + break; | |
| 857 | + } | |
| 858 | + | |
| 859 | + default: | |
| 860 | + putc(ch); | |
| 861 | + ch = in.read(); | |
| 862 | + break; | |
| 863 | + } | |
| 864 | + } | |
| 865 | + } | |
| 866 | + | |
| 867 | + /** | |
| 868 | + * Scan a character. The current character should be | |
| 869 | + * the opening ' of the character constant. | |
| 870 | + */ | |
| 871 | + private void scanCharacter() throws IOException { | |
| 872 | + token = CHARVAL; | |
| 873 | + | |
| 874 | + switch (ch = in.read()) { | |
| 875 | + case '\\': | |
| 876 | + int c = scanEscapeChar(); | |
| 877 | + charValue = (char)((c >= 0) ? c : 0); | |
| 878 | + break; | |
| 879 | + | |
| 880 | + case '\'': | |
| 881 | + // There are two standard problems this case deals with. One | |
| 882 | + // is the malformed single quote constant (i.e. the programmer | |
| 883 | + // uses ''' instead of '\'') and the other is the empty | |
| 884 | + // character constant (i.e. ''). Just consume any number of | |
| 885 | + // single quotes and emit an error message. | |
| 886 | + charValue = 0; | |
| 887 | + env.error(pos, "invalid.char.constant"); | |
| 888 | + ch = in.read(); | |
| 889 | + while (ch == '\'') { | |
| 890 | + ch = in.read(); | |
| 891 | + } | |
| 892 | + return; | |
| 893 | + | |
| 894 | + case '\r': | |
| 895 | + case '\n': | |
| 896 | + charValue = 0; | |
| 897 | + env.error(pos, "invalid.char.constant"); | |
| 898 | + return; | |
| 899 | + | |
| 900 | + default: | |
| 901 | + charValue = (char)ch; | |
| 902 | + ch = in.read(); | |
| 903 | + break; | |
| 904 | + } | |
| 905 | + | |
| 906 | + if (ch == '\'') { | |
| 907 | + ch = in.read(); | |
| 908 | + } else { | |
| 909 | + env.error(pos, "invalid.char.constant"); | |
| 910 | + while (true) { | |
| 911 | + switch (ch) { | |
| 912 | + case '\'': | |
| 913 | + ch = in.read(); | |
| 914 | + return; | |
| 915 | + case ';': | |
| 916 | + case '\n': | |
| 917 | + case EOF: | |
| 918 | + return; | |
| 919 | + default: | |
| 920 | + ch = in.read(); | |
| 921 | + } | |
| 922 | + } | |
| 923 | + } | |
| 924 | + } | |
| 925 | + | |
| 926 | + /** | |
| 927 | + * Scan an Identifier. The current character should | |
| 928 | + * be the first character of the identifier. | |
| 929 | + */ | |
| 930 | + private void scanIdentifier() throws IOException { | |
| 931 | + count = 0; | |
| 932 | + | |
| 933 | + while (true) { | |
| 934 | + putc(ch); | |
| 935 | + switch (ch = in.read()) { | |
| 936 | + case 'a': case 'b': case 'c': case 'd': case 'e': | |
| 937 | + case 'f': case 'g': case 'h': case 'i': case 'j': | |
| 938 | + case 'k': case 'l': case 'm': case 'n': case 'o': | |
| 939 | + case 'p': case 'q': case 'r': case 's': case 't': | |
| 940 | + case 'u': case 'v': case 'w': case 'x': case 'y': | |
| 941 | + case 'z': | |
| 942 | + case 'A': case 'B': case 'C': case 'D': case 'E': | |
| 943 | + case 'F': case 'G': case 'H': case 'I': case 'J': | |
| 944 | + case 'K': case 'L': case 'M': case 'N': case 'O': | |
| 945 | + case 'P': case 'Q': case 'R': case 'S': case 'T': | |
| 946 | + case 'U': case 'V': case 'W': case 'X': case 'Y': | |
| 947 | + case 'Z': | |
| 948 | + case '0': case '1': case '2': case '3': case '4': | |
| 949 | + case '5': case '6': case '7': case '8': case '9': | |
| 950 | + case '$': case '_': | |
| 951 | + break; | |
| 952 | + | |
| 953 | + default: | |
| 954 | + if (!Character.isJavaLetterOrDigit((char)ch)) { | |
| 955 | + idValue = Identifier.lookup(bufferString()); | |
| 956 | + token = idValue.getType(); | |
| 957 | + return; | |
| 958 | + } | |
| 959 | + } | |
| 960 | + } | |
| 961 | + } | |
| 962 | + | |
| 963 | + /** | |
| 964 | + * The ending position of the current token | |
| 965 | + */ | |
| 966 | + // Note: This should be part of the pos itself. | |
| 967 | + public long getEndPos() { | |
| 968 | + return in.pos; | |
| 969 | + } | |
| 970 | + | |
| 971 | + /** | |
| 972 | + * If the current token is IDENT, return the identifier occurrence. | |
| 973 | + * It will be freshly allocated. | |
| 974 | + */ | |
| 975 | + public IdentifierToken getIdToken() { | |
| 976 | + return (token != IDENT) ? null : new IdentifierToken(pos, idValue); | |
| 977 | + } | |
| 978 | + | |
| 979 | + /** | |
| 980 | + * Scan the next token. | |
| 981 | + * @return the position of the previous token. | |
| 982 | + */ | |
| 983 | + public long scan() throws IOException { | |
| 984 | + return xscan(); | |
| 985 | + } | |
| 986 | + | |
| 987 | + protected long xscan() throws IOException { | |
| 988 | + final ScannerInputReader in = this.in; | |
| 989 | + long retPos = pos; | |
| 990 | + prevPos = in.pos; | |
| 991 | + docComment = null; | |
| 992 | + while (true) { | |
| 993 | + pos = in.pos; | |
| 994 | + | |
| 995 | + switch (ch) { | |
| 996 | + case EOF: | |
| 997 | + token = EOF; | |
| 998 | + return retPos; | |
| 999 | + | |
| 1000 | + case '\n': | |
| 1001 | + if (scanComments) { | |
| 1002 | + ch = ' '; | |
| 1003 | + // Avoid this path the next time around. | |
| 1004 | + // Do not just call in.read; we want to present | |
| 1005 | + // a null token (and also avoid read-ahead). | |
| 1006 | + token = COMMENT; | |
| 1007 | + return retPos; | |
| 1008 | + } | |
| 1009 | + case ' ': | |
| 1010 | + case '\t': | |
| 1011 | + case '\f': | |
| 1012 | + ch = in.read(); | |
| 1013 | + break; | |
| 1014 | + | |
| 1015 | + case '/': | |
| 1016 | + switch (ch = in.read()) { | |
| 1017 | + case '/': | |
| 1018 | + // Parse a // comment | |
| 1019 | + while (((ch = in.read()) != EOF) && (ch != '\n')); | |
| 1020 | + if (scanComments) { | |
| 1021 | + token = COMMENT; | |
| 1022 | + return retPos; | |
| 1023 | + } | |
| 1024 | + break; | |
| 1025 | + | |
| 1026 | + case '*': | |
| 1027 | + ch = in.read(); | |
| 1028 | + if (ch == '*') { | |
| 1029 | + docComment = scanDocComment(); | |
| 1030 | + } else { | |
| 1031 | + skipComment(); | |
| 1032 | + } | |
| 1033 | + if (scanComments) { | |
| 1034 | + return retPos; | |
| 1035 | + } | |
| 1036 | + break; | |
| 1037 | + | |
| 1038 | + case '=': | |
| 1039 | + ch = in.read(); | |
| 1040 | + token = ASGDIV; | |
| 1041 | + return retPos; | |
| 1042 | + | |
| 1043 | + default: | |
| 1044 | + token = DIV; | |
| 1045 | + return retPos; | |
| 1046 | + } | |
| 1047 | + break; | |
| 1048 | + | |
| 1049 | + case '"': | |
| 1050 | + scanString(); | |
| 1051 | + return retPos; | |
| 1052 | + | |
| 1053 | + case '\'': | |
| 1054 | + scanCharacter(); | |
| 1055 | + return retPos; | |
| 1056 | + | |
| 1057 | + case '0': case '1': case '2': case '3': case '4': | |
| 1058 | + case '5': case '6': case '7': case '8': case '9': | |
| 1059 | + scanNumber(); | |
| 1060 | + return retPos; | |
| 1061 | + | |
| 1062 | + case '.': | |
| 1063 | + switch (ch = in.read()) { | |
| 1064 | + case '0': case '1': case '2': case '3': case '4': | |
| 1065 | + case '5': case '6': case '7': case '8': case '9': | |
| 1066 | + count = 0; | |
| 1067 | + putc('.'); | |
| 1068 | + scanReal(); | |
| 1069 | + break; | |
| 1070 | + default: | |
| 1071 | + token = FIELD; | |
| 1072 | + } | |
| 1073 | + return retPos; | |
| 1074 | + | |
| 1075 | + case '{': | |
| 1076 | + ch = in.read(); | |
| 1077 | + token = LBRACE; | |
| 1078 | + return retPos; | |
| 1079 | + | |
| 1080 | + case '}': | |
| 1081 | + ch = in.read(); | |
| 1082 | + token = RBRACE; | |
| 1083 | + return retPos; | |
| 1084 | + | |
| 1085 | + case '(': | |
| 1086 | + ch = in.read(); | |
| 1087 | + token = LPAREN; | |
| 1088 | + return retPos; | |
| 1089 | + | |
| 1090 | + case ')': | |
| 1091 | + ch = in.read(); | |
| 1092 | + token = RPAREN; | |
| 1093 | + return retPos; | |
| 1094 | + | |
| 1095 | + case '[': | |
| 1096 | + ch = in.read(); | |
| 1097 | + token = LSQBRACKET; | |
| 1098 | + return retPos; | |
| 1099 | + | |
| 1100 | + case ']': | |
| 1101 | + ch = in.read(); | |
| 1102 | + token = RSQBRACKET; | |
| 1103 | + return retPos; | |
| 1104 | + | |
| 1105 | + case ',': | |
| 1106 | + ch = in.read(); | |
| 1107 | + token = COMMA; | |
| 1108 | + return retPos; | |
| 1109 | + | |
| 1110 | + case ';': | |
| 1111 | + ch = in.read(); | |
| 1112 | + token = SEMICOLON; | |
| 1113 | + return retPos; | |
| 1114 | + | |
| 1115 | + case '?': | |
| 1116 | + ch = in.read(); | |
| 1117 | + token = QUESTIONMARK; | |
| 1118 | + return retPos; | |
| 1119 | + | |
| 1120 | + case '~': | |
| 1121 | + ch = in.read(); | |
| 1122 | + token = BITNOT; | |
| 1123 | + return retPos; | |
| 1124 | + | |
| 1125 | + case ':': | |
| 1126 | + ch = in.read(); | |
| 1127 | + token = COLON; | |
| 1128 | + return retPos; | |
| 1129 | + | |
| 1130 | + case '-': | |
| 1131 | + switch (ch = in.read()) { | |
| 1132 | + case '-': | |
| 1133 | + ch = in.read(); | |
| 1134 | + token = DEC; | |
| 1135 | + return retPos; | |
| 1136 | + | |
| 1137 | + case '=': | |
| 1138 | + ch = in.read(); | |
| 1139 | + token = ASGSUB; | |
| 1140 | + return retPos; | |
| 1141 | + } | |
| 1142 | + token = SUB; | |
| 1143 | + return retPos; | |
| 1144 | + | |
| 1145 | + case '+': | |
| 1146 | + switch (ch = in.read()) { | |
| 1147 | + case '+': | |
| 1148 | + ch = in.read(); | |
| 1149 | + token = INC; | |
| 1150 | + return retPos; | |
| 1151 | + | |
| 1152 | + case '=': | |
| 1153 | + ch = in.read(); | |
| 1154 | + token = ASGADD; | |
| 1155 | + return retPos; | |
| 1156 | + } | |
| 1157 | + token = ADD; | |
| 1158 | + return retPos; | |
| 1159 | + | |
| 1160 | + case '<': | |
| 1161 | + switch (ch = in.read()) { | |
| 1162 | + case '<': | |
| 1163 | + if ((ch = in.read()) == '=') { | |
| 1164 | + ch = in.read(); | |
| 1165 | + token = ASGLSHIFT; | |
| 1166 | + return retPos; | |
| 1167 | + } | |
| 1168 | + token = LSHIFT; | |
| 1169 | + return retPos; | |
| 1170 | + | |
| 1171 | + case '=': | |
| 1172 | + ch = in.read(); | |
| 1173 | + token = LE; | |
| 1174 | + return retPos; | |
| 1175 | + } | |
| 1176 | + token = LT; | |
| 1177 | + return retPos; | |
| 1178 | + | |
| 1179 | + case '>': | |
| 1180 | + switch (ch = in.read()) { | |
| 1181 | + case '>': | |
| 1182 | + switch (ch = in.read()) { | |
| 1183 | + case '=': | |
| 1184 | + ch = in.read(); | |
| 1185 | + token = ASGRSHIFT; | |
| 1186 | + return retPos; | |
| 1187 | + | |
| 1188 | + case '>': | |
| 1189 | + if ((ch = in.read()) == '=') { | |
| 1190 | + ch = in.read(); | |
| 1191 | + token = ASGURSHIFT; | |
| 1192 | + return retPos; | |
| 1193 | + } | |
| 1194 | + token = URSHIFT; | |
| 1195 | + return retPos; | |
| 1196 | + } | |
| 1197 | + token = RSHIFT; | |
| 1198 | + return retPos; | |
| 1199 | + | |
| 1200 | + case '=': | |
| 1201 | + ch = in.read(); | |
| 1202 | + token = GE; | |
| 1203 | + return retPos; | |
| 1204 | + } | |
| 1205 | + token = GT; | |
| 1206 | + return retPos; | |
| 1207 | + | |
| 1208 | + case '|': | |
| 1209 | + switch (ch = in.read()) { | |
| 1210 | + case '|': | |
| 1211 | + ch = in.read(); | |
| 1212 | + token = OR; | |
| 1213 | + return retPos; | |
| 1214 | + | |
| 1215 | + case '=': | |
| 1216 | + ch = in.read(); | |
| 1217 | + token = ASGBITOR; | |
| 1218 | + return retPos; | |
| 1219 | + } | |
| 1220 | + token = BITOR; | |
| 1221 | + return retPos; | |
| 1222 | + | |
| 1223 | + case '&': | |
| 1224 | + switch (ch = in.read()) { | |
| 1225 | + case '&': | |
| 1226 | + ch = in.read(); | |
| 1227 | + token = AND; | |
| 1228 | + return retPos; | |
| 1229 | + | |
| 1230 | + case '=': | |
| 1231 | + ch = in.read(); | |
| 1232 | + token = ASGBITAND; | |
| 1233 | + return retPos; | |
| 1234 | + } | |
| 1235 | + token = BITAND; | |
| 1236 | + return retPos; | |
| 1237 | + | |
| 1238 | + case '=': | |
| 1239 | + if ((ch = in.read()) == '=') { | |
| 1240 | + ch = in.read(); | |
| 1241 | + token = EQ; | |
| 1242 | + return retPos; | |
| 1243 | + } | |
| 1244 | + token = ASSIGN; | |
| 1245 | + return retPos; | |
| 1246 | + | |
| 1247 | + case '%': | |
| 1248 | + if ((ch = in.read()) == '=') { | |
| 1249 | + ch = in.read(); | |
| 1250 | + token = ASGREM; | |
| 1251 | + return retPos; | |
| 1252 | + } | |
| 1253 | + token = REM; | |
| 1254 | + return retPos; | |
| 1255 | + | |
| 1256 | + case '^': | |
| 1257 | + if ((ch = in.read()) == '=') { | |
| 1258 | + ch = in.read(); | |
| 1259 | + token = ASGBITXOR; | |
| 1260 | + return retPos; | |
| 1261 | + } | |
| 1262 | + token = BITXOR; | |
| 1263 | + return retPos; | |
| 1264 | + | |
| 1265 | + case '!': | |
| 1266 | + if ((ch = in.read()) == '=') { | |
| 1267 | + ch = in.read(); | |
| 1268 | + token = NE; | |
| 1269 | + return retPos; | |
| 1270 | + } | |
| 1271 | + token = NOT; | |
| 1272 | + return retPos; | |
| 1273 | + | |
| 1274 | + case '*': | |
| 1275 | + if ((ch = in.read()) == '=') { | |
| 1276 | + ch = in.read(); | |
| 1277 | + token = ASGMUL; | |
| 1278 | + return retPos; | |
| 1279 | + } | |
| 1280 | + token = MUL; | |
| 1281 | + return retPos; | |
| 1282 | + | |
| 1283 | + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': | |
| 1284 | + case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': | |
| 1285 | + case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': | |
| 1286 | + case 's': case 't': case 'u': case 'v': case 'w': case 'x': | |
| 1287 | + case 'y': case 'z': | |
| 1288 | + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': | |
| 1289 | + case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': | |
| 1290 | + case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': | |
| 1291 | + case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': | |
| 1292 | + case 'Y': case 'Z': | |
| 1293 | + case '$': case '_': | |
| 1294 | + scanIdentifier(); | |
| 1295 | + return retPos; | |
| 1296 | + | |
| 1297 | + case '\u001a': | |
| 1298 | + // Our one concession to DOS. | |
| 1299 | + if ((ch = in.read()) == EOF) { | |
| 1300 | + token = EOF; | |
| 1301 | + return retPos; | |
| 1302 | + } | |
| 1303 | + env.error(pos, "funny.char"); | |
| 1304 | + ch = in.read(); | |
| 1305 | + break; | |
| 1306 | + | |
| 1307 | + | |
| 1308 | + default: | |
| 1309 | + if (Character.isJavaLetter((char)ch)) { | |
| 1310 | + scanIdentifier(); | |
| 1311 | + return retPos; | |
| 1312 | + } | |
| 1313 | + env.error(pos, "funny.char"); | |
| 1314 | + ch = in.read(); | |
| 1315 | + break; | |
| 1316 | + } | |
| 1317 | + } | |
| 1318 | + } | |
| 1319 | + | |
| 1320 | + /** | |
| 1321 | + * Scan to a matching '}', ']' or ')'. The current token must be | |
| 1322 | + * a '{', '[' or '('; | |
| 1323 | + */ | |
| 1324 | + public void match(int open, int close) throws IOException { | |
| 1325 | + int depth = 1; | |
| 1326 | + | |
| 1327 | + while (true) { | |
| 1328 | + scan(); | |
| 1329 | + if (token == open) { | |
| 1330 | + depth++; | |
| 1331 | + } else if (token == close) { | |
| 1332 | + if (--depth == 0) { | |
| 1333 | + return; | |
| 1334 | + } | |
| 1335 | + } else if (token == EOF) { | |
| 1336 | + env.error(pos, "unbalanced.paren"); | |
| 1337 | + return; | |
| 1338 | + } | |
| 1339 | + } | |
| 1340 | + } | |
| 1341 | +} | |
| @@ -0,0 +1,242 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +import java.io.IOException; | |
| 29 | +import java.io.InputStream; | |
| 30 | +import java.io.InputStreamReader; | |
| 31 | +import java.io.BufferedReader; | |
| 32 | +import java.io.FilterReader; | |
| 33 | +import java.io.UnsupportedEncodingException; | |
| 34 | + | |
| 35 | +/** | |
| 36 | + * An input stream for java programs. The stream treats either "\n", "\r" | |
| 37 | + * or "\r\n" as the end of a line, it always returns \n. It also parses | |
| 38 | + * UNICODE characters expressed as \uffff. However, if it sees "\\", the | |
| 39 | + * second slash cannot begin a unicode sequence. It keeps track of the current | |
| 40 | + * position in the input stream. | |
| 41 | + * | |
| 42 | + * WARNING: The contents of this source file are not part of any | |
| 43 | + * supported API. Code that depends on them does so at its own risk: | |
| 44 | + * they are subject to change or removal without notice. | |
| 45 | + * | |
| 46 | + * @author Arthur van Hoff | |
| 47 | + */ | |
| 48 | + | |
| 49 | +public | |
| 50 | +class ScannerInputReader extends FilterReader implements Constants { | |
| 51 | + // A note. This class does not really properly subclass FilterReader. | |
| 52 | + // Since this class only overrides the single character read method, | |
| 53 | + // and not the multi-character read method, any use of the latter | |
| 54 | + // will not work properly. Any attempt to use this code outside of | |
| 55 | + // the compiler should take that into account. | |
| 56 | + // | |
| 57 | + // For efficiency, it might be worth moving this code to Scanner and | |
| 58 | + // getting rid of this class. | |
| 59 | + | |
| 60 | + Environment env; | |
| 61 | + long pos; | |
| 62 | + | |
| 63 | + private long chpos; | |
| 64 | + private int pushBack = -1; | |
| 65 | + | |
| 66 | + public ScannerInputReader(Environment env, InputStream in) | |
| 67 | + throws UnsupportedEncodingException | |
| 68 | + { | |
| 69 | + // ScannerInputStream has been modified to no longer use | |
| 70 | + // BufferedReader. It now does its own buffering for | |
| 71 | + // performance. | |
| 72 | + super(env.getCharacterEncoding() != null ? | |
| 73 | + new InputStreamReader(in, env.getCharacterEncoding()) : | |
| 74 | + new InputStreamReader(in)); | |
| 75 | + | |
| 76 | + // Start out the buffer empty. | |
| 77 | + currentIndex = 0; | |
| 78 | + numChars = 0; | |
| 79 | + | |
| 80 | + this.env = env; | |
| 81 | + chpos = Scanner.LINEINC; | |
| 82 | + } | |
| 83 | + | |
| 84 | + //------------------------------------------------------------ | |
| 85 | + // Buffering code. | |
| 86 | + | |
| 87 | + // The size of our buffer. | |
| 88 | + private static final int BUFFERLEN = 10 * 1024; | |
| 89 | + | |
| 90 | + // A character buffer. | |
| 91 | + private final char[] buffer = new char[BUFFERLEN]; | |
| 92 | + | |
| 93 | + // The index of the next character to be "read" from the buffer. | |
| 94 | + private int currentIndex; | |
| 95 | + | |
| 96 | + // The number of characters in the buffer. -1 if EOF is reached. | |
| 97 | + private int numChars; | |
| 98 | + | |
| 99 | + /** | |
| 100 | + * Get the next character from our buffer. | |
| 101 | + * Note: this method has been inlined by hand in the `read' method | |
| 102 | + * below. Any changes made to this method should be equally applied | |
| 103 | + * to that code. | |
| 104 | + */ | |
| 105 | + private int getNextChar() throws IOException { | |
| 106 | + // Check to see if we have either run out of characters in our | |
| 107 | + // buffer or gotten to EOF on a previous call. | |
| 108 | + if (currentIndex >= numChars) { | |
| 109 | + numChars = in.read(buffer); | |
| 110 | + if (numChars == -1) { | |
| 111 | + // We have reached EOF. | |
| 112 | + return -1; | |
| 113 | + } | |
| 114 | + | |
| 115 | + // No EOF. currentIndex points to first char in buffer. | |
| 116 | + currentIndex = 0; | |
| 117 | + } | |
| 118 | + | |
| 119 | + return buffer[currentIndex++]; | |
| 120 | + } | |
| 121 | + | |
| 122 | + //------------------------------------------------------------ | |
| 123 | + | |
| 124 | + public int read(char[] buffer, int off, int len) { | |
| 125 | + throw new CompilerError( | |
| 126 | + "ScannerInputReader is not a fully implemented reader."); | |
| 127 | + } | |
| 128 | + | |
| 129 | + public int read() throws IOException { | |
| 130 | + pos = chpos; | |
| 131 | + chpos += Scanner.OFFSETINC; | |
| 132 | + | |
| 133 | + int c = pushBack; | |
| 134 | + if (c == -1) { | |
| 135 | + getchar: try { | |
| 136 | + // Here the call... | |
| 137 | + // c = getNextChar(); | |
| 138 | + // has been inlined by hand for performance. | |
| 139 | + | |
| 140 | + if (currentIndex >= numChars) { | |
| 141 | + numChars = in.read(buffer); | |
| 142 | + if (numChars == -1) { | |
| 143 | + // We have reached EOF. | |
| 144 | + c = -1; | |
| 145 | + break getchar; | |
| 146 | + } | |
| 147 | + | |
| 148 | + // No EOF. currentIndex points to first char in buffer. | |
| 149 | + currentIndex = 0; | |
| 150 | + } | |
| 151 | + c = buffer[currentIndex++]; | |
| 152 | + | |
| 153 | + } catch (java.io.CharConversionException e) { | |
| 154 | + env.error(pos, "invalid.encoding.char"); | |
| 155 | + // this is fatal error | |
| 156 | + return -1; | |
| 157 | + } | |
| 158 | + } else { | |
| 159 | + pushBack = -1; | |
| 160 | + } | |
| 161 | + | |
| 162 | + // parse special characters | |
| 163 | + switch (c) { | |
| 164 | + case -2: | |
| 165 | + // -2 is a special code indicating a pushback of a backslash that | |
| 166 | + // definitely isn't the start of a unicode sequence. | |
| 167 | + return '\\'; | |
| 168 | + | |
| 169 | + case '\\': | |
| 170 | + if ((c = getNextChar()) != 'u') { | |
| 171 | + pushBack = (c == '\\' ? -2 : c); | |
| 172 | + return '\\'; | |
| 173 | + } | |
| 174 | + // we have a unicode sequence | |
| 175 | + chpos += Scanner.OFFSETINC; | |
| 176 | + while ((c = getNextChar()) == 'u') { | |
| 177 | + chpos += Scanner.OFFSETINC; | |
| 178 | + } | |
| 179 | + | |
| 180 | + // unicode escape sequence | |
| 181 | + int d = 0; | |
| 182 | + for (int i = 0 ; i < 4 ; i++, chpos += Scanner.OFFSETINC, c = getNextChar()) { | |
| 183 | + switch (c) { | |
| 184 | + case '0': case '1': case '2': case '3': case '4': | |
| 185 | + case '5': case '6': case '7': case '8': case '9': | |
| 186 | + d = (d << 4) + c - '0'; | |
| 187 | + break; | |
| 188 | + | |
| 189 | + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': | |
| 190 | + d = (d << 4) + 10 + c - 'a'; | |
| 191 | + break; | |
| 192 | + | |
| 193 | + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': | |
| 194 | + d = (d << 4) + 10 + c - 'A'; | |
| 195 | + break; | |
| 196 | + | |
| 197 | + default: | |
| 198 | + env.error(pos, "invalid.escape.char"); | |
| 199 | + pushBack = c; | |
| 200 | + return d; | |
| 201 | + } | |
| 202 | + } | |
| 203 | + pushBack = c; | |
| 204 | + | |
| 205 | + // To read the following line, switch \ and /... | |
| 206 | + // Handle /u000a, /u000A, /u000d, /u000D properly as | |
| 207 | + // line terminators as per JLS 3.4, even though they are encoded | |
| 208 | + // (this properly respects the order given in JLS 3.2). | |
| 209 | + switch (d) { | |
| 210 | + case '\n': | |
| 211 | + chpos += Scanner.LINEINC; | |
| 212 | + return '\n'; | |
| 213 | + case '\r': | |
| 214 | + if ((c = getNextChar()) != '\n') { | |
| 215 | + pushBack = c; | |
| 216 | + } else { | |
| 217 | + chpos += Scanner.OFFSETINC; | |
| 218 | + } | |
| 219 | + chpos += Scanner.LINEINC; | |
| 220 | + return '\n'; | |
| 221 | + default: | |
| 222 | + return d; | |
| 223 | + } | |
| 224 | + | |
| 225 | + case '\n': | |
| 226 | + chpos += Scanner.LINEINC; | |
| 227 | + return '\n'; | |
| 228 | + | |
| 229 | + case '\r': | |
| 230 | + if ((c = getNextChar()) != '\n') { | |
| 231 | + pushBack = c; | |
| 232 | + } else { | |
| 233 | + chpos += Scanner.OFFSETINC; | |
| 234 | + } | |
| 235 | + chpos += Scanner.LINEINC; | |
| 236 | + return '\n'; | |
| 237 | + | |
| 238 | + default: | |
| 239 | + return c; | |
| 240 | + } | |
| 241 | + } | |
| 242 | +} | |
| @@ -0,0 +1,39 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Syntax errors, should always be caught inside the | |
| 30 | + * parser for error recovery. | |
| 31 | + * | |
| 32 | + * WARNING: The contents of this source file are not part of any | |
| 33 | + * supported API. Code that depends on them does so at its own risk: | |
| 34 | + * they are subject to change or removal without notice. | |
| 35 | + */ | |
| 36 | + | |
| 37 | +public | |
| 38 | +class SyntaxError extends Exception { | |
| 39 | +} | |
| @@ -0,0 +1,455 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package sun.tools.java; | |
| 27 | + | |
| 28 | +import java.util.Hashtable; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * This class represents an Java Type.<p> | |
| 32 | + * | |
| 33 | + * It encapsulates an Java type signature and it provides | |
| 34 | + * quick access to the components of the type. Note that | |
| 35 | + * all types are hashed into a hashtable (typeHash), that | |
| 36 | + * means that each distinct type is only allocated once, | |
| 37 | + * saving space and making equality checks cheap.<p> | |
| 38 | + * | |
| 39 | + * For simple types use the constants defined in this class. | |
| 40 | + * (Type.tInt, Type.tShort, ...). To create complex types use | |
| 41 | + * the static methods Type.tArray, Type.tMethod or Type.tClass. | |
| 42 | + * | |
| 43 | + * For classes, arrays and method types a sub class of class | |
| 44 | + * type is created which defines the extra type components. | |
| 45 | + * | |
| 46 | + * WARNING: The contents of this source file are not part of any | |
| 47 | + * supported API. Code that depends on them does so at its own risk: | |
| 48 | + * they are subject to change or removal without notice. | |
| 49 | + * | |
| 50 | + * @see ArrayType | |
| 51 | + * @see ClassType | |
| 52 | + * @see MethodType | |
| 53 | + * @author Arthur van Hoff | |
| 54 | + */ | |
| 55 | +public | |
| 56 | +class Type implements Constants { | |
| 57 | + /** | |
| 58 | + * This hashtable is used to cache types | |
| 59 | + */ | |
| 60 | + private static final Hashtable typeHash = new Hashtable(231); | |
| 61 | + | |
| 62 | + /** | |
| 63 | + * The TypeCode of this type. The value of this field is one | |
| 64 | + * of the TC_* contant values defined in Constants. | |
| 65 | + * @see Constants | |
| 66 | + */ | |
| 67 | + protected int typeCode; | |
| 68 | + | |
| 69 | + /** | |
| 70 | + * The TypeSignature of this type. This type signature is | |
| 71 | + * equivalent to the runtime type signatures used by the | |
| 72 | + * interpreter. | |
| 73 | + */ | |
| 74 | + protected String typeSig; | |
| 75 | + | |
| 76 | + /* | |
| 77 | + * Predefined types. | |
| 78 | + */ | |
| 79 | + public static final Type noArgs[] = new Type[0]; | |
| 80 | + public static final Type tError = new Type(TC_ERROR, "?"); | |
| 81 | + public static final Type tPackage = new Type(TC_ERROR, "."); | |
| 82 | + public static final Type tNull = new Type(TC_NULL, "*"); | |
| 83 | + public static final Type tVoid = new Type(TC_VOID, SIG_VOID); | |
| 84 | + public static final Type tBoolean = new Type(TC_BOOLEAN, SIG_BOOLEAN); | |
| 85 | + public static final Type tByte = new Type(TC_BYTE, SIG_BYTE); | |
| 86 | + public static final Type tChar = new Type(TC_CHAR, SIG_CHAR); | |
| 87 | + public static final Type tShort = new Type(TC_SHORT, SIG_SHORT); | |
| 88 | + public static final Type tInt = new Type(TC_INT, SIG_INT); | |
| 89 | + public static final Type tFloat = new Type(TC_FLOAT, SIG_FLOAT); | |
| 90 | + public static final Type tLong = new Type(TC_LONG, SIG_LONG); | |
| 91 | + public static final Type tDouble = new Type(TC_DOUBLE, SIG_DOUBLE); | |
| 92 | + public static final Type tObject = Type.tClass(idJavaLangObject); | |
| 93 | + public static final Type tClassDesc = Type.tClass(idJavaLangClass); | |
| 94 | + public static final Type tString = Type.tClass(idJavaLangString); | |
| 95 | + public static final Type tCloneable = Type.tClass(idJavaLangCloneable); | |
| 96 | + public static final Type tSerializable = Type.tClass(idJavaIoSerializable); | |
| 97 | + | |
| 98 | + /** | |
| 99 | + * Create a type given a typecode and a type signature. | |
| 100 | + */ | |
| 101 | + protected Type(int typeCode, String typeSig) { | |
| 102 | + this.typeCode = typeCode; | |
| 103 | + this.typeSig = typeSig; | |
| 104 | + typeHash.put(typeSig, this); | |
| 105 | + } | |
| 106 | + | |
| 107 | + /** | |
| 108 | + * Return the Java type signature. | |
| 109 | + */ | |
| 110 | + public final String getTypeSignature() { | |
| 111 | + return typeSig; | |
| 112 | + } | |
| 113 | + | |
| 114 | + /** | |
| 115 | + * Return the type code. | |
| 116 | + */ | |
| 117 | + public final int getTypeCode() { | |
| 118 | + return typeCode; | |
| 119 | + } | |
| 120 | + | |
| 121 | + /** | |
| 122 | + * Return the type mask. The bits in this mask correspond | |
| 123 | + * to the TM_* constants defined in Constants. Only one bit | |
| 124 | + * is set at a type. | |
| 125 | + * @see Constants | |
| 126 | + */ | |
| 127 | + public final int getTypeMask() { | |
| 128 | + return 1 << typeCode; | |
| 129 | + } | |
| 130 | + | |
| 131 | + /** | |
| 132 | + * Check for a certain type. | |
| 133 | + */ | |
| 134 | + public final boolean isType(int tc) { | |
| 135 | + return typeCode == tc; | |
| 136 | + } | |
| 137 | + | |
| 138 | + /** | |
| 139 | + * Check to see if this is the bogus type "array of void" | |
| 140 | + * | |
| 141 | + * Although this highly degenerate "type" is not constructable from | |
| 142 | + * the grammar, the Parser accepts it. Rather than monkey with the | |
| 143 | + * Parser, we check for the bogus type at specific points and give | |
| 144 | + * a nice error. | |
| 145 | + */ | |
| 146 | + public boolean isVoidArray() { | |
| 147 | + // a void type is not a void array. | |
| 148 | + if (!isType(TC_ARRAY)) { | |
| 149 | + return false; | |
| 150 | + } | |
| 151 | + // If this is an array, find out what its element type is. | |
| 152 | + Type type = this; | |
| 153 | + while (type.isType(TC_ARRAY)) | |
| 154 | + type = type.getElementType(); | |
| 155 | + | |
| 156 | + return type.isType(TC_VOID); | |
| 157 | + } | |
| 158 | + | |
| 159 | + | |
| 160 | + /** | |
| 161 | + * Check for a certain set of types. | |
| 162 | + */ | |
| 163 | + public final boolean inMask(int tm) { | |
| 164 | + return ((1 << typeCode) & tm) != 0; | |
| 165 | + } | |
| 166 | + | |
| 167 | + /** | |
| 168 | + * Create an array type. | |
| 169 | + */ | |
| 170 | + public static synchronized Type tArray(Type elem) { | |
| 171 | + String sig = new String(SIG_ARRAY + elem.getTypeSignature()); | |
| 172 | + Type t = (Type)typeHash.get(sig); | |
| 173 | + if (t == null) { | |
| 174 | + t = new ArrayType(sig, elem); | |
| 175 | + } | |
| 176 | + return t; | |
| 177 | + } | |
| 178 | + | |
| 179 | + /** | |
| 180 | + * Return the element type of an array type. Only works | |
| 181 | + * for array types. | |
| 182 | + */ | |
| 183 | + public Type getElementType() { | |
| 184 | + throw new CompilerError("getElementType"); | |
| 185 | + } | |
| 186 | + | |
| 187 | + /** | |
| 188 | + * Return the array dimension. Only works for | |
| 189 | + * array types. | |
| 190 | + */ | |
| 191 | + public int getArrayDimension() { | |
| 192 | + return 0; | |
| 193 | + } | |
| 194 | + | |
| 195 | + /** | |
| 196 | + * Create a class type. | |
| 197 | + * @arg className the fully qualified class name | |
| 198 | + */ | |
| 199 | + public static synchronized Type tClass(Identifier className) { | |
| 200 | + if (className.isInner()) { | |
| 201 | + Type t = tClass(mangleInnerType(className)); | |
| 202 | + if (t.getClassName() != className) | |
| 203 | + // Somebody got here first with a mangled name. | |
| 204 | + // (Perhaps it came from a binary.) | |
| 205 | + changeClassName(t.getClassName(), className); | |
| 206 | + return t; | |
| 207 | + } | |
| 208 | + // see if we've cached the object in the Identifier | |
| 209 | + if (className.typeObject != null) { | |
| 210 | + return className.typeObject; | |
| 211 | + } | |
| 212 | + String sig = | |
| 213 | + new String(SIG_CLASS + | |
| 214 | + className.toString().replace('.', SIGC_PACKAGE) + | |
| 215 | + SIG_ENDCLASS); | |
| 216 | + Type t = (Type)typeHash.get(sig); | |
| 217 | + if (t == null) { | |
| 218 | + t = new ClassType(sig, className); | |
| 219 | + } | |
| 220 | + | |
| 221 | + className.typeObject = t; // cache the Type object in the Identifier | |
| 222 | + return t; | |
| 223 | + } | |
| 224 | + | |
| 225 | + /** | |
| 226 | + * Return the ClassName. Only works on class types. | |
| 227 | + */ | |
| 228 | + public Identifier getClassName() { | |
| 229 | + throw new CompilerError("getClassName:" + this); | |
| 230 | + } | |
| 231 | + | |
| 232 | + /** | |
| 233 | + * Given an inner identifier, return the non-inner, mangled | |
| 234 | + * representation used to manage signatures. | |
| 235 | + * | |
| 236 | + * Note: It is changed to 'public' for Jcov file generation. | |
| 237 | + * (see Assembler.java) | |
| 238 | + */ | |
| 239 | + | |
| 240 | + public static Identifier mangleInnerType(Identifier className) { | |
| 241 | + // Map "pkg.Foo. Bar" to "pkg.Foo$Bar". | |
| 242 | + if (!className.isInner()) return className; | |
| 243 | + Identifier mname = Identifier.lookup( | |
| 244 | + className.getFlatName().toString(). | |
| 245 | + replace('.', SIGC_INNERCLASS) ); | |
| 246 | + if (mname.isInner()) throw new CompilerError("mangle "+mname); | |
| 247 | + return Identifier.lookup(className.getQualifier(), mname); | |
| 248 | + } | |
| 249 | + | |
| 250 | + /** | |
| 251 | + * We have learned that a signature means something other | |
| 252 | + * that what we thought it meant. Live with it: Change all | |
| 253 | + * affected data structures to reflect the new name of the old type. | |
| 254 | + * <p> | |
| 255 | + * (This is necessary because of an ambiguity between the | |
| 256 | + * low-level signatures of inner types and their manglings. | |
| 257 | + * Note that the latter are also valid class names.) | |
| 258 | + */ | |
| 259 | + static void changeClassName(Identifier oldName, Identifier newName) { | |
| 260 | + // Note: If we are upgrading "pkg.Foo$Bar" to "pkg.Foo. Bar", | |
| 261 | + // we assume someone else will come along and deal with any types | |
| 262 | + // inner within Bar. So, there's only one change to make. | |
| 263 | + ((ClassType)Type.tClass(oldName)).className = newName; | |
| 264 | + } | |
| 265 | + | |
| 266 | + /** | |
| 267 | + * Create a method type with no arguments. | |
| 268 | + */ | |
| 269 | + public static synchronized Type tMethod(Type ret) { | |
| 270 | + return tMethod(ret, noArgs); | |
| 271 | + } | |
| 272 | + | |
| 273 | + /** | |
| 274 | + * Create a method type with arguments. | |
| 275 | + */ | |
| 276 | + public static synchronized Type tMethod(Type returnType, Type argTypes[]) { | |
| 277 | + StringBuffer buf = new StringBuffer(); | |
| 278 | + buf.append(SIG_METHOD); | |
| 279 | + for (int i = 0 ; i < argTypes.length ; i++) { | |
| 280 | + buf.append(argTypes[i].getTypeSignature()); | |
| 281 | + } | |
| 282 | + buf.append(SIG_ENDMETHOD); | |
| 283 | + buf.append(returnType.getTypeSignature()); | |
| 284 | + | |
| 285 | + String sig = buf.toString(); | |
| 286 | + Type t = (Type)typeHash.get(sig); | |
| 287 | + if (t == null) { | |
| 288 | + t = new MethodType(sig, returnType, argTypes); | |
| 289 | + } | |
| 290 | + return t; | |
| 291 | + } | |
| 292 | + | |
| 293 | + /** | |
| 294 | + * Return the return type. Only works for method types. | |
| 295 | + */ | |
| 296 | + public Type getReturnType() { | |
| 297 | + throw new CompilerError("getReturnType"); | |
| 298 | + } | |
| 299 | + | |
| 300 | + /** | |
| 301 | + * Return the argument types. Only works for method types. | |
| 302 | + */ | |
| 303 | + public Type getArgumentTypes()[] { | |
| 304 | + throw new CompilerError("getArgumentTypes"); | |
| 305 | + } | |
| 306 | + | |
| 307 | + /** | |
| 308 | + * Create a Type from an Java type signature. | |
| 309 | + * @exception CompilerError invalid type signature. | |
| 310 | + */ | |
| 311 | + public static synchronized Type tType(String sig) { | |
| 312 | + Type t = (Type)typeHash.get(sig); | |
| 313 | + if (t != null) { | |
| 314 | + return t; | |
| 315 | + } | |
| 316 | + | |
| 317 | + switch (sig.charAt(0)) { | |
| 318 | + case SIGC_ARRAY: | |
| 319 | + return Type.tArray(tType(sig.substring(1))); | |
| 320 | + | |
| 321 | + case SIGC_CLASS: | |
| 322 | + return Type.tClass(Identifier.lookup(sig.substring(1, sig.length() - 1).replace(SIGC_PACKAGE, '.'))); | |
| 323 | + | |
| 324 | + case SIGC_METHOD: { | |
| 325 | + Type argv[] = new Type[8]; | |
| 326 | + int argc = 0; | |
| 327 | + int i, j; | |
| 328 | + | |
| 329 | + for (i = 1 ; sig.charAt(i) != SIGC_ENDMETHOD ; i = j) { | |
| 330 | + for (j = i ; sig.charAt(j) == SIGC_ARRAY ; j++); | |
| 331 | + if (sig.charAt(j++) == SIGC_CLASS) { | |
| 332 | + while (sig.charAt(j++) != SIGC_ENDCLASS); | |
| 333 | + } | |
| 334 | + if (argc == argv.length) { | |
| 335 | + Type newargv[] = new Type[argc * 2]; | |
| 336 | + System.arraycopy(argv, 0, newargv, 0, argc); | |
| 337 | + argv = newargv; | |
| 338 | + } | |
| 339 | + argv[argc++] = tType(sig.substring(i, j)); | |
| 340 | + } | |
| 341 | + | |
| 342 | + Type argtypes[] = new Type[argc]; | |
| 343 | + System.arraycopy(argv, 0, argtypes, 0, argc); | |
| 344 | + return Type.tMethod(tType(sig.substring(i + 1)), argtypes); | |
| 345 | + } | |
| 346 | + } | |
| 347 | + | |
| 348 | + throw new CompilerError("invalid TypeSignature:" + sig); | |
| 349 | + } | |
| 350 | + | |
| 351 | + /** | |
| 352 | + * Check if the type arguments are the same. | |
| 353 | + * @return true if both types are method types and the | |
| 354 | + * argument types are identical. | |
| 355 | + */ | |
| 356 | + public boolean equalArguments(Type t) { | |
| 357 | + return false; | |
| 358 | + } | |
| 359 | + | |
| 360 | + /** | |
| 361 | + * Return the amount of space this type takes up on the | |
| 362 | + * Java operand stack. For a method this is equal to the | |
| 363 | + * total space taken up by the arguments. | |
| 364 | + */ | |
| 365 | + public int stackSize() { | |
| 366 | + switch (typeCode) { | |
| 367 | + case TC_ERROR: | |
| 368 | + case TC_VOID: | |
| 369 | + return 0; | |
| 370 | + case TC_BOOLEAN: | |
| 371 | + case TC_BYTE: | |
| 372 | + case TC_SHORT: | |
| 373 | + case TC_CHAR: | |
| 374 | + case TC_INT: | |
| 375 | + case TC_FLOAT: | |
| 376 | + case TC_ARRAY: | |
| 377 | + case TC_CLASS: | |
| 378 | + return 1; | |
| 379 | + case TC_LONG: | |
| 380 | + case TC_DOUBLE: | |
| 381 | + return 2; | |
| 382 | + } | |
| 383 | + throw new CompilerError("stackSize " + toString()); | |
| 384 | + } | |
| 385 | + | |
| 386 | + /** | |
| 387 | + * Return the type code offset. This offset can be added to | |
| 388 | + * an opcode to get the right opcode type. Most opcodes | |
| 389 | + * are ordered: int, long, float, double, array. For | |
| 390 | + * example: iload, lload fload, dload, aload. So the | |
| 391 | + * appropriate opcode is iadd + type.getTypeCodeOffset(). | |
| 392 | + */ | |
| 393 | + public int getTypeCodeOffset() { | |
| 394 | + switch (typeCode) { | |
| 395 | + case TC_BOOLEAN: | |
| 396 | + case TC_BYTE: | |
| 397 | + case TC_SHORT: | |
| 398 | + case TC_CHAR: | |
| 399 | + case TC_INT: | |
| 400 | + return 0; | |
| 401 | + case TC_LONG: | |
| 402 | + return 1; | |
| 403 | + case TC_FLOAT: | |
| 404 | + return 2; | |
| 405 | + case TC_DOUBLE: | |
| 406 | + return 3; | |
| 407 | + case TC_NULL: | |
| 408 | + case TC_ARRAY: | |
| 409 | + case TC_CLASS: | |
| 410 | + return 4; | |
| 411 | + } | |
| 412 | + throw new CompilerError("invalid typecode: " + typeCode); | |
| 413 | + } | |
| 414 | + | |
| 415 | + /** | |
| 416 | + * Convert a Type to a string, if abbrev is true class names are | |
| 417 | + * not fully qualified, if ret is true the return type is included. | |
| 418 | + */ | |
| 419 | + public String typeString(String id, boolean abbrev, boolean ret) { | |
| 420 | + String s = null; | |
| 421 | + | |
| 422 | + switch (typeCode) { | |
| 423 | + case TC_NULL: s = "null"; break; | |
| 424 | + case TC_VOID: s = "void"; break; | |
| 425 | + case TC_BOOLEAN: s = "boolean"; break; | |
| 426 | + case TC_BYTE: s = "byte"; break; | |
| 427 | + case TC_CHAR: s = "char"; break; | |
| 428 | + case TC_SHORT: s = "short"; break; | |
| 429 | + case TC_INT: s = "int"; break; | |
| 430 | + case TC_LONG: s = "long"; break; | |
| 431 | + case TC_FLOAT: s = "float"; break; | |
| 432 | + case TC_DOUBLE: s = "double"; break; | |
| 433 | + case TC_ERROR: s = "<error>"; | |
| 434 | + if (this==tPackage) s = "<package>"; | |
| 435 | + break; | |
| 436 | + default: s = "unknown"; | |
| 437 | + } | |
| 438 | + | |
| 439 | + return (id.length() > 0) ? s + " " + id : s; | |
| 440 | + } | |
| 441 | + | |
| 442 | + /** | |
| 443 | + * Create a type string, given an identifier. | |
| 444 | + */ | |
| 445 | + public String typeString(String id) { | |
| 446 | + return typeString(id, false, true); | |
| 447 | + } | |
| 448 | + | |
| 449 | + /** | |
| 450 | + * Convert to a String | |
| 451 | + */ | |
| 452 | + public String toString() { | |
| 453 | + return typeString("", false, true); | |
| 454 | + } | |
| 455 | +} | |
| @@ -0,0 +1,39 @@ | ||
| 1 | +<../../../../../mkconfig | |
| 2 | + | |
| 3 | +TARG=\ | |
| 4 | + AmbiguousClass.dis\ | |
| 5 | + AmbiguousMember.dis\ | |
| 6 | + ArrayType.dis\ | |
| 7 | + BinaryAttribute.dis\ | |
| 8 | + BinaryClass.dis\ | |
| 9 | + BinaryCode.dis\ | |
| 10 | + BinaryConstantPool.dis\ | |
| 11 | + BinaryExceptionHandler.dis\ | |
| 12 | + BinaryMember.dis\ | |
| 13 | + ClassDeclaration.dis\ | |
| 14 | + ClassDefinition.dis\ | |
| 15 | + ClassFile.dis\ | |
| 16 | + ClassNotFound.dis\ | |
| 17 | + ClassPath.dis\ | |
| 18 | + ClassType.dis\ | |
| 19 | + CompilerError.dis\ | |
| 20 | + Constants.dis\ | |
| 21 | + Environment.dis\ | |
| 22 | + Identifier.dis\ | |
| 23 | + IdentifierToken.dis\ | |
| 24 | + Imports.dis\ | |
| 25 | + MemberDefinition.dis\ | |
| 26 | + MethodSet.dis\ | |
| 27 | + MethodType.dis\ | |
| 28 | + Package.dis\ | |
| 29 | + Parser.dis\ | |
| 30 | + ParserActions.dis\ | |
| 31 | + RuntimeConstants.dis\ | |
| 32 | + Scanner.dis\ | |
| 33 | + ScannerInputReader.dis\ | |
| 34 | + SyntaxError.dis\ | |
| 35 | + Type.dis\ | |
| 36 | + | |
| 37 | +DISBIN=$ROOT/java/dis/java/java/sun/tools/java | |
| 38 | + | |
| 39 | +<$ROOT/mkfiles/mkjava | |