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 | ||