0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041: package org.netbeans.modules.java.source.usages;
0042:
0043: import com.sun.tools.javac.code.Attribute;
0044: import com.sun.tools.javac.code.BoundKind;
0045: import com.sun.tools.javac.code.Flags;
0046: import static com.sun.tools.javac.code.Flags.*;
0047: import static com.sun.tools.javac.code.Kinds.*;
0048: import com.sun.tools.javac.code.Scope;
0049: import com.sun.tools.javac.code.Source;
0050: import com.sun.tools.javac.code.Symbol;
0051: import com.sun.tools.javac.code.Symbol.ClassSymbol;
0052: import com.sun.tools.javac.code.Symbol.CompletionFailure;
0053: import com.sun.tools.javac.code.Symbol.MethodSymbol;
0054: import com.sun.tools.javac.code.Symbol.PackageSymbol;
0055: import com.sun.tools.javac.code.Symbol.VarSymbol;
0056: import com.sun.tools.javac.code.Symtab;
0057: import com.sun.tools.javac.code.Type;
0058: import com.sun.tools.javac.code.Type.ClassType;
0059: import com.sun.tools.javac.code.Type.ErrorType;
0060: import com.sun.tools.javac.code.Type.ForAll;
0061: import com.sun.tools.javac.code.Type.MethodType;
0062: import com.sun.tools.javac.code.Type.TypeVar;
0063: import com.sun.tools.javac.code.Type.WildcardType;
0064: import com.sun.tools.javac.code.Types;
0065: import static com.sun.tools.javac.code.TypeTags.*;
0066: import com.sun.tools.javac.jvm.ClassReader;
0067: import com.sun.tools.javac.model.JavacTypes;
0068: import com.sun.tools.javac.util.Context;
0069: import com.sun.tools.javac.util.List;
0070: import com.sun.tools.javac.util.ListBuffer;
0071: import com.sun.tools.javac.util.Log;
0072: import com.sun.tools.javac.util.Name;
0073: import com.sun.tools.javac.util.Name.Table;
0074: import com.sun.tools.javac.util.Pair;
0075: import com.sun.tools.javadoc.JavadocClassReader;
0076:
0077: import java.io.BufferedReader;
0078: import java.io.IOException;
0079: import java.io.InputStreamReader;
0080: import java.io.Reader;
0081: import java.io.StringReader;
0082:
0083: import javax.lang.model.type.TypeMirror;
0084: import javax.tools.JavaFileObject;
0085:
0086: import org.netbeans.modules.java.source.parsing.FileObjects;
0087: import org.openide.ErrorManager;
0088:
0089: /**
0090: *
0091: * @author Jan Lahoda
0092: */
0093: public class SymbolClassReader extends JavadocClassReader {
0094:
0095: public static void preRegister(final Context context,
0096: final boolean loadDocEnv) {
0097: context.put(classReaderKey, new Context.Factory<ClassReader>() {
0098: public ClassReader make() {
0099: return new SymbolClassReader(context, loadDocEnv);
0100: }
0101: });
0102: }
0103:
0104: private Symtab syms;
0105: private Table table;
0106: private Types types;
0107: private JavacTypes jTypes;
0108: private Log logger;
0109: private Source source;
0110: private boolean sigEnterPhase;
0111:
0112: private char[] buffer;
0113: private int currentBufferIndex;
0114:
0115: private boolean readingClassSignature = false;
0116: private boolean readingEnclMethod = false;
0117: private List<Type> missingTypeVariables = List.nil();
0118: private List<Type> foundTypeVariables = List.nil();
0119:
0120: protected SymbolClassReader(Context context, boolean loadDocEnv) {
0121: super (context, loadDocEnv);
0122: syms = Symtab.instance(context);
0123: table = Table.instance(context);
0124: types = Types.instance(context);
0125: jTypes = JavacTypes.instance(context);
0126: logger = Log.instance(context);
0127: source = Source.instance(context);
0128: allowGenerics = true;
0129: allowVarargs = true;
0130: allowAnnotations = true;
0131:
0132: buffer = new char[127];
0133: }
0134:
0135: private void addCharToBuffer(char c) {
0136: if (currentBufferIndex >= buffer.length) {
0137: char[] newBuffer = new char[buffer.length * 2];
0138:
0139: System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
0140: buffer = newBuffer;
0141: }
0142: buffer[currentBufferIndex++] = c;
0143: }
0144:
0145: private void clearBuffer() {
0146: currentBufferIndex = 0;
0147: }
0148:
0149: private int bufferLength() {
0150: return currentBufferIndex;
0151: }
0152:
0153: protected @Override
0154: void fillIn(ClassSymbol c) {
0155: Symbol oldCurrentOwner = currentOwner;
0156: try {
0157: fillInImpl(c);
0158: } finally {
0159: currentOwner = oldCurrentOwner;
0160: }
0161: }
0162:
0163: private boolean isSignatureFile(final JavaFileObject jfo) {
0164: if (jfo instanceof FileObjects.Base) {
0165: return ((FileObjects.Base) jfo).getExt().equals(
0166: FileObjects.SIG);
0167: } else {
0168: //Should never happen, but for sure
0169: return jfo.toUri().toString().endsWith(
0170: '.' + FileObjects.SIG);
0171: }
0172: }
0173:
0174: private void fillInImpl(ClassSymbol c) {
0175: if (c.classfile == null
0176: || c.classfile.getKind() != JavaFileObject.Kind.CLASS
0177: || !isSignatureFile(c.classfile)) {
0178: //will throw a CompletionFailure
0179: super .fillIn(c);
0180: return;
0181: }
0182:
0183: try {
0184: final BufferedReader r = new BufferedReader(
0185: new InputStreamReader(
0186: c.classfile.openInputStream(), "UTF-8")); // NOI18N
0187: try {
0188: int magic = r.read();
0189: if (magic != 'G') {
0190: throw new IOException("Wrong signature file: "
0191: + c.classfile.toUri());
0192: }
0193: fillInFromSig(c, r);
0194: if (!missingTypeVariables.isEmpty()
0195: && !foundTypeVariables.isEmpty()) {
0196: List<Type> missing = missingTypeVariables;
0197: List<Type> found = foundTypeVariables;
0198: missingTypeVariables = List.nil();
0199: foundTypeVariables = List.nil();
0200: ClassType ct = (ClassType) currentOwner.type;
0201: ct.super type_field = types.subst(
0202: ct.super type_field, missing, found);
0203: ct.interfaces_field = types.subst(
0204: ct.interfaces_field, missing, found);
0205: } else if (missingTypeVariables.isEmpty() != foundTypeVariables
0206: .isEmpty()) {
0207: Name name = missingTypeVariables.head.tsym.name;
0208: throw badClassFile("undecl.type.var", name);
0209: }
0210: } finally {
0211: try {
0212: r.close();
0213: } catch (IOException ex) {
0214: ErrorManager.getDefault().notify(ex);
0215: }
0216: missingTypeVariables = List.nil();
0217: foundTypeVariables = List.nil();
0218: }
0219: } catch (IOException e) {
0220: throw new CompletionFailure(c, e.getMessage()).initCause(e);
0221: }
0222: }
0223:
0224: private void fillInFromSig(ClassSymbol c, Reader r)
0225: throws IOException {
0226: ClassType ct = (ClassType) c.type;
0227:
0228: // allocate scope for members
0229: c.members_field = new Scope(c);
0230:
0231: currentOwner = c;
0232:
0233: // prepare type variable table
0234: typevars = typevars.dup(currentOwner);
0235: if (ct.getEnclosingType().tag == CLASS)
0236: enterTypevars(ct.getEnclosingType());
0237:
0238: // read flags, or skip if this is an inner class
0239: long flags = readFlags(r) & ~(UNATTRIBUTED | ACYCLIC)
0240: | FROMCLASS;
0241: c.flags_field = flags;
0242:
0243: int read = r.read();
0244: readingClassSignature = true;
0245: try {
0246: //read type variables:
0247: List<TypeVar> typevarsList;
0248:
0249: if (read == '<') {
0250: typevarsList = readTypeParamsWithName(r, c);
0251: read = r.read();
0252: } else {
0253: typevarsList = List.<TypeVar> nil();
0254: }
0255:
0256: ct.typarams_field = (List<Type>) ((List<?>) typevarsList);
0257:
0258: assert read == 'N' : read;
0259:
0260: Name name = readPlainNameIntoTable(r);
0261:
0262: if (name != c.flatname) {
0263: throw badClassFile("class.file.wrong.class", name);
0264: }
0265:
0266: // handle enclosing method for anonymous and local classes
0267: if ((read = r.read()) != ';') {
0268: readEnclosingMethodAttr(r, c, read);
0269: }
0270:
0271: read = r.read();
0272:
0273: if (read != ';') {
0274: ct.super type_field = readType(r, read); //XXX: Maybe add ct.supertype_field.tsym.erase () as the ClassReader does
0275: } else {
0276: //noType as the parent, for j.l.Object:
0277: ct.super type_field = Type.noType;
0278: }
0279:
0280: if (ct.super type_field.getClass() == Type.class) {
0281: if (!ct.super type_field.isPrimitive()) {
0282: System.err.println("PROBLEM");
0283: System.err.println("c=" + c.flatname.toString());
0284: }
0285: }
0286:
0287: //read super interfaces:
0288: List<Type> super Interfaces = List.nil();
0289:
0290: while ((read = r.read()) != ';') {
0291: super Interfaces = super Interfaces.prepend(readType(r,
0292: read)); //XXX: Maybe add erase () as the ClassReader does
0293: }
0294:
0295: ct.interfaces_field = super Interfaces.reverse();
0296:
0297: } finally {
0298: readingClassSignature = false;
0299: }
0300:
0301: //handle innerclasses
0302: while ((read = r.read()) != ';') {
0303: assert read == 'N';
0304:
0305: String innerClassName = readPlainName(r);
0306: ClassSymbol innerClass = enterClass(
0307: findName(innerClassName), c);
0308:
0309: markInnerClassOwner(c, innerClass, readFlags(r));
0310: }
0311:
0312: read = r.read();
0313:
0314: assert read == '\n' || read == (-1) : c.classfile + ", char: "
0315: + ((char) read) + read;
0316:
0317: Symbol s;
0318:
0319: while ((s = readMember(r)) != null) {
0320: enterMember(c, s);
0321: }
0322:
0323: attachAnnotations(c, r);
0324:
0325: typevars = typevars.leave();
0326: }
0327:
0328: void readEnclosingMethodAttr(Reader r, ClassSymbol self, int read)
0329: throws IOException {
0330: readingEnclMethod = true;
0331: try {
0332: assert read == 'N' : read;
0333: // sym is a nested class with an "Enclosing Method" attribute
0334: // remove sym from it's current owners scope and place it in
0335: // the scope specified by the attribute
0336: //jlahoda: the owner may already be set correctly, do not remove from it in such a case:
0337: if (self.owner.kind == PCK) {
0338: self.owner.members().remove(self);
0339: }
0340: ClassSymbol c = enterClass(readPlainNameIntoTable(r));
0341: MethodSymbol m = null;
0342: read = r.read();
0343: if (read == 'N') {
0344: Name methodName = readPlainNameIntoTable(r);
0345: read = r.read();
0346: assert read == '(' : read;
0347: List<Type> paramsTypes = List.nil();
0348: while ((read = r.read()) != ')') {
0349: paramsTypes = paramsTypes
0350: .prepend(readType(r, read));
0351: }
0352: paramsTypes = paramsTypes.reverse();
0353: read = r.read();
0354: assert read == '(' : read;
0355: List<Type> throwsTypes = List.nil();
0356: while ((read = r.read()) != ')') {
0357: throwsTypes = throwsTypes
0358: .prepend(readType(r, read));
0359: }
0360: throwsTypes = throwsTypes.reverse();
0361: Type returnType = readType(r, r.read());
0362: assert (read = r.read()) == ';' : read;
0363: MethodType methodType = new MethodType(paramsTypes,
0364: returnType, throwsTypes, syms.methodClass);
0365:
0366: m = findMethod(methodName, methodType, c.members_field,
0367: self.flags());
0368: if (methodName != null && methodType != null
0369: && m == null)
0370: throw badClassFile("bad.enclosing.method", self);
0371: }
0372: self.name = simpleBinaryName(self.flatname, c.flatname);
0373: self.owner = m != null ? m : c;
0374: if (self.name.len == 0)
0375: self.fullname = null;
0376: else
0377: self.fullname = ClassSymbol.formFullName(self.name,
0378: self.owner);
0379:
0380: if (m != null) {
0381: ((ClassType) self.type).setEnclosingType(m.type);
0382: } else if ((self.flags_field & STATIC) == 0) {
0383: ((ClassType) self.type).setEnclosingType(c.type);
0384: } else {
0385: ((ClassType) self.type).setEnclosingType(Type.noType);
0386: }
0387: enterTypevars(self);
0388: if (!missingTypeVariables.isEmpty()) {
0389: ListBuffer<Type> typeVars = new ListBuffer<Type>();
0390: for (Type typevar : missingTypeVariables) {
0391: typeVars.append(findTypeVar(typevar.tsym.name));
0392: }
0393: foundTypeVariables = typeVars.toList();
0394: } else {
0395: foundTypeVariables = List.nil();
0396: }
0397: } finally {
0398: readingEnclMethod = false;
0399: }
0400: }
0401:
0402: private MethodSymbol findMethod(Name name, MethodType type,
0403: Scope scope, long flags) {
0404: if (name == null || type == null)
0405: return null;
0406:
0407: for (Scope.Entry e = scope.lookup(name); e.scope != null; e = e
0408: .next())
0409: if (e.sym.kind == MTH
0410: && isSameBinaryType(e.sym.type.asMethodType(), type))
0411: return (MethodSymbol) e.sym;
0412:
0413: if (name != table.init)
0414: // not a constructor
0415: return null;
0416: if ((flags & INTERFACE) != 0)
0417: // no enclosing instance
0418: return null;
0419: if (type.getParameterTypes().isEmpty())
0420: // no parameters
0421: return null;
0422:
0423: // A constructor of an inner class.
0424: // Remove the first argument (the enclosing instance)
0425: type = new MethodType(type.getParameterTypes().tail, type
0426: .getReturnType(), type.getThrownTypes(),
0427: syms.methodClass);
0428: // Try searching again
0429: return findMethod(name, type, scope, flags);
0430: }
0431:
0432: private void markInnerClassOwner(ClassSymbol owner,
0433: ClassSymbol innerClass, long flags) {
0434: innerClass.complete();
0435: innerClass.flags_field = flags & ~(UNATTRIBUTED | ACYCLIC)
0436: | FROMCLASS;
0437: if ((innerClass.flags_field & STATIC) == 0) {
0438: ((ClassType) innerClass.type).setEnclosingType(owner.type);
0439: if (innerClass.erasure_field != null)
0440: ((ClassType) innerClass.erasure_field)
0441: .setEnclosingType(types.erasure(owner.type));
0442: }
0443: enterMember(owner, innerClass);
0444: }
0445:
0446: private List<TypeVar> readTypeParams(Symbol owner, Reader r)
0447: throws IOException {
0448: int read;
0449: List<TypeVar> result = List.<TypeVar> nil();
0450: while ((read = r.read()) != '>') {
0451: clearBuffer();
0452:
0453: addCharToBuffer((char) read);
0454:
0455: while ((read = r.read()) != ':') {
0456: addCharToBuffer((char) read);
0457: }
0458:
0459: Name typeName = findName(buffer, bufferLength());
0460:
0461: TypeVar tvar = null;
0462:
0463: if (sigEnterPhase) {
0464: List<Type> last = null;
0465: for (List<Type> l = missingTypeVariables; l.nonEmpty(); l = l.tail) {
0466: if (typeName == l.head.tsym.name) {
0467: tvar = (TypeVar) l.head;
0468: if (last != null) {
0469: last.tail = l.tail;
0470: } else {
0471: missingTypeVariables = l.tail;
0472: }
0473: break;
0474: }
0475: last = l;
0476: }
0477: if (tvar == null) {
0478: tvar = new TypeVar(typeName, owner, syms.botType);
0479: }
0480: typevars.enter(tvar.tsym);
0481: } else {
0482: tvar = (TypeVar) findTypeVar(typeName);
0483: }
0484:
0485: List<Type> bounds = List.<Type> nil();
0486:
0487: while ((read = r.read()) != ';') {
0488: bounds = bounds.prepend(readType(r, read));
0489: }
0490:
0491: bounds = bounds.reverse();
0492:
0493: if (!sigEnterPhase) {
0494: types.setBounds(tvar, bounds, null);
0495: }
0496:
0497: result = result.prepend(tvar);
0498: }
0499:
0500: return result;
0501: }
0502:
0503: private List<TypeVar> readTypeParamsWithName(Reader r, Symbol owner)
0504: throws IOException {
0505: LoggingReader lr = new LoggingReader(r);
0506:
0507: boolean oldSigEnterPhase = sigEnterPhase;
0508:
0509: sigEnterPhase = true;
0510:
0511: try {
0512: readTypeParams(owner, lr);
0513: } finally {
0514: sigEnterPhase = oldSigEnterPhase;
0515: }
0516:
0517: StringReader copy = new StringReader(lr.logged.toString());
0518: List<TypeVar> result = readTypeParams(owner, copy);
0519:
0520: copy.close();
0521:
0522: return result.reverse();
0523: }
0524:
0525: private static final class LoggingReader extends Reader {
0526:
0527: private Reader delegateTo;
0528: private StringBuilder logged = new StringBuilder();
0529:
0530: public LoggingReader(Reader delegateTo) {
0531: this .delegateTo = delegateTo;
0532: }
0533:
0534: @Override
0535: public int read(char[] cbuf, int off, int len)
0536: throws IOException {
0537: int result = delegateTo.read(cbuf, off, len);
0538:
0539: logged.append(cbuf, off, result);
0540:
0541: return result;
0542: }
0543:
0544: @Override
0545: public void close() throws IOException {
0546: }
0547:
0548: }
0549:
0550: private java.util.List<? extends TypeMirror> readTypeParams(Reader r)
0551: throws IOException {
0552: java.util.List<TypeMirror> params = new java.util.ArrayList<TypeMirror>();
0553: int read;
0554:
0555: while ((read = r.read()) != '>') {
0556: params.add(readType(r, read));
0557: }
0558:
0559: return params;
0560: }
0561:
0562: private String readPlainName(Reader r) throws IOException {
0563: clearBuffer();
0564:
0565: int read;
0566:
0567: while ((read = r.read()) != ';') {
0568: addCharToBuffer((char) read);
0569: }
0570:
0571: return new String(buffer, 0, bufferLength());
0572: }
0573:
0574: private String readName(Reader r) throws IOException {
0575: int read = r.read();
0576:
0577: assert read == 'N' : (char) read;
0578:
0579: return readPlainName(r);
0580: }
0581:
0582: private Name readPlainNameIntoTable(Reader r) throws IOException {
0583: clearBuffer();
0584:
0585: int read;
0586:
0587: while ((read = r.read()) != ';') {
0588: addCharToBuffer((char) read);
0589: }
0590:
0591: return findName(buffer, bufferLength());
0592: }
0593:
0594: private Name readNameIntoTable(Reader r) throws IOException {
0595: int read = r.read();
0596:
0597: assert read == 'N' : (char) read;
0598:
0599: return readPlainNameIntoTable(r);
0600: }
0601:
0602: private long readPlainFlags(Reader r) throws IOException {
0603: return Long.parseLong(readPlainName(r), 16);
0604: }
0605:
0606: private long readFlags(Reader r) throws IOException {
0607: int read = r.read();
0608:
0609: assert read == 'M';
0610:
0611: return readPlainFlags(r);
0612: }
0613:
0614: private Type readType(Reader r, int read) throws IOException {
0615: switch (read) {
0616: case 'Z':
0617: return syms.booleanType;
0618: case 'B':
0619: return syms.byteType;
0620: case 'S':
0621: return syms.shortType;
0622: case 'I':
0623: return syms.intType;
0624: case 'J':
0625: return syms.longType;
0626: case 'C':
0627: return syms.charType;
0628: case 'F':
0629: return syms.floatType;
0630: case 'D':
0631: return syms.doubleType;
0632: case 'V':
0633: return syms.voidType;
0634: case 'L':
0635: return readReferenceType(r, null);
0636: case '[':
0637: return (Type) jTypes.getArrayType(readType(r, r.read()));
0638: case 'R':
0639: return new ErrorType(readPlainNameIntoTable(r),
0640: syms.noSymbol);
0641: case 'Q':
0642: Name name = readPlainNameIntoTable(r);
0643: if (sigEnterPhase)
0644: return Type.noType;
0645: else
0646: return findTypeVar(name);
0647: case '+':
0648: return new WildcardType(readType(r, r.read()),
0649: BoundKind.EXTENDS, syms.boundClass);
0650: case '-':
0651: return new WildcardType(readType(r, r.read()),
0652: BoundKind.SUPER, syms.boundClass);
0653: case '?':
0654: return new WildcardType(syms.objectType, BoundKind.UNBOUND,
0655: syms.boundClass);
0656: default:
0657: throw new IllegalArgumentException("Completing: "
0658: + ((ClassSymbol) currentOwner).flatname.toString()
0659: + ", read=" + ((char) read) + ":" + read);
0660: }
0661: }
0662:
0663: /** Find type variable with given name in `typevars' scope.
0664: */
0665: Type findTypeVar(Name name) {
0666: Scope.Entry e = typevars.lookup(name);
0667: if (e.scope != null) {
0668: return e.sym.type;
0669: } else {
0670: if (readingClassSignature || readingEnclMethod) {
0671: // While reading the class attribute, the supertypes
0672: // might refer to a type variable from an enclosing element
0673: // (method or class).
0674: // If the type variable is defined in the enclosing class,
0675: // we can actually find it in
0676: // currentOwner.owner.type.getTypeArguments()
0677: // However, until we have read the enclosing method attribute
0678: // we don't know for sure if this owner is correct. It could
0679: // be a method and there is no way to tell before reading the
0680: // enclosing method attribute.
0681: TypeVar t = new TypeVar(name, currentOwner,
0682: syms.botType);
0683: missingTypeVariables = missingTypeVariables.prepend(t);
0684: // System.err.println("Missing type var " + name);
0685: return t;
0686: }
0687: throw badClassFile("undecl.type.var", name);
0688: }
0689: }
0690:
0691: private Name findName(CharSequence s) {
0692: char[] data = s.toString().toCharArray();
0693:
0694: return findName(data, data.length);
0695: }
0696:
0697: private Name findName(char[] data, int len) {
0698: return Name.fromChars(table, data, 0, len);
0699: }
0700:
0701: private Type readReferenceType(Reader r, Type outer)
0702: throws IOException {
0703: clearBuffer();
0704:
0705: int read;
0706:
0707: while (";<".indexOf(read = r.read()) == (-1)) {
0708: addCharToBuffer((char) read);
0709: }
0710:
0711: Name name = findName(buffer, bufferLength());
0712: ClassSymbol symbol = outer != null ? enterClass(name,
0713: outer.tsym) : enterClass(name);
0714:
0715: Symbol oldCurrentOwner = currentOwner;
0716: java.util.List<? extends TypeMirror> typeParams = read == '<' ? readTypeParams(r)
0717: : null;//Collections.<TypeMirror>emptyList();
0718: Type result;
0719:
0720: if (typeParams != null) {
0721: result = new ClassType(outer != null ? outer : Type.noType,
0722: List.from(typeParams.toArray(new Type[0])), symbol) {
0723: boolean completed = false;
0724:
0725: public Type getEnclosingType() {
0726: if (!completed) {
0727: completed = true;
0728: tsym.complete();
0729: Type enclosingType = tsym.type
0730: .getEnclosingType();
0731: if (enclosingType != Type.noType) {
0732: List<Type> typeArgs = super
0733: .getEnclosingType().allparams();
0734: List<Type> typeParams = enclosingType
0735: .allparams();
0736: if (typeParams.length() != typeArgs
0737: .length()) {
0738: // no "rare" types
0739: super .setEnclosingType(types
0740: .erasure(enclosingType));
0741: } else {
0742: super .setEnclosingType(types.subst(
0743: enclosingType, typeParams,
0744: typeArgs));
0745: }
0746: } else {
0747: super .setEnclosingType(Type.noType);
0748: }
0749: }
0750: return super .getEnclosingType();
0751: }
0752:
0753: public void setEnclosingType(Type outer) {
0754: throw new UnsupportedOperationException();
0755: }
0756: };
0757: } else {
0758: result = outer != null ? new ClassType(outer, List
0759: .<Type> nil(), symbol) : symbol.erasure(types);
0760: }
0761:
0762: currentOwner = oldCurrentOwner;
0763:
0764: if (read == '<') {
0765: read = r.read();
0766: if (read == '$') {
0767: return readReferenceType(r, result);
0768: }
0769: assert read == ';' : (char) read;
0770: }
0771:
0772: return result;
0773: }
0774:
0775: private Symbol readMember(Reader r) throws IOException {
0776: int read = r.read();
0777:
0778: if ('E' == read) {
0779: return readExecutableMember(r);
0780: }
0781:
0782: if ('A' == read) {
0783: return readField(r);
0784: }
0785:
0786: if ('W' == read)
0787: return null;
0788:
0789: if (read == (-1))
0790: return null;
0791:
0792: throw new IllegalArgumentException("Unknown type: " + read);
0793: }
0794:
0795: private Symbol readExecutableMember(Reader r) throws IOException {
0796: long flags = readFlags(r);
0797:
0798: //Equivalent to ClassReader.adjustFlags ()
0799: //When the mathod is a bridge and covariant return types are not allowed
0800: //clean SYNTHETIC flag
0801: if ((flags & Flags.BRIDGE) != 0 && !allowCovRetTypes) {
0802: flags &= ~SYNTHETIC;
0803: }
0804:
0805: typevars = typevars.dup(currentOwner);
0806:
0807: MethodSymbol method = new MethodSymbol(flags, null, null,
0808: currentOwner);
0809:
0810: List<TypeVar> typevarsList = null;
0811: int read = r.read();
0812:
0813: if (read == '<') {
0814: typevarsList = readTypeParamsWithName(r, method);
0815:
0816: read = r.read();
0817: }
0818:
0819: assert read == 'N' : read;
0820:
0821: method.name = readPlainNameIntoTable(r);
0822:
0823: read = r.read();
0824:
0825: assert read == '(' : read;
0826:
0827: List<VarSymbol> params = List.nil();
0828: List<Type> paramsTypes = List.nil();
0829:
0830: while ((read = r.read()) != ')') {
0831: assert read == 'M';
0832:
0833: long argFlags = readPlainFlags(r);
0834: Type argType = readType(r, r.read());
0835: Name argName = readNameIntoTable(r);
0836:
0837: paramsTypes = paramsTypes.prepend(argType);
0838:
0839: params = params.prepend(new VarSymbol(argFlags, argName,
0840: argType, null));
0841: }
0842:
0843: paramsTypes = paramsTypes.reverse();
0844: params = params.reverse();
0845: read = r.read();
0846:
0847: assert read == '(' : read;
0848:
0849: List<Type> throwsTypes = List.nil();
0850:
0851: while ((read = r.read()) != ')') {
0852: throwsTypes = throwsTypes.prepend(readType(r, read));
0853: }
0854:
0855: Type returnType = readType(r, r.read());
0856: Type methodType = new MethodType(paramsTypes, returnType,
0857: throwsTypes.reverse(), syms.methodClass/*???*/);
0858: ;
0859:
0860: if (typevarsList != null) {
0861: methodType = new ForAll(
0862: (List<Type>) ((List<?>) typevarsList), methodType);
0863: }
0864:
0865: method.type = methodType;
0866:
0867: method.params = params;
0868:
0869: //change owner for all arguments:
0870: for (VarSymbol s : params) {
0871: s.owner = method;
0872: }
0873:
0874: attachAnnotations(method, r);
0875:
0876: if ((read = r.read()) != ';') {
0877: annotate.later(new AnnotationDefaultCompleter(method,
0878: readAnnotationValue(r, read)));
0879: }
0880:
0881: typevars = typevars.leave();
0882:
0883: read = r.read();
0884:
0885: while (read == ' ')
0886: read = r.read();
0887:
0888: assert read == '\n' || read == (-1) : read;
0889:
0890: return method;
0891: }
0892:
0893: private Symbol readField(Reader r) throws IOException {
0894: long flags = readFlags(r);
0895:
0896: Type type = readType(r, r.read());
0897: Name name = readNameIntoTable(r);
0898:
0899: Object constantValue = readConstantField(r);
0900:
0901: VarSymbol field = new VarSymbol(flags, name, type, currentOwner);
0902:
0903: field.setData(constantValue);
0904:
0905: attachAnnotations(field, r);
0906:
0907: int read = r.read();
0908:
0909: while (read == ' ')
0910: read = r.read();
0911:
0912: assert read == '\n' || read == (-1) : read;
0913:
0914: return field;
0915: }
0916:
0917: private String readEscapedString(Reader r) throws IOException {
0918: String value = readPlainName(r);
0919: StringBuffer result = new StringBuffer();
0920:
0921: for (int cntr = 0; cntr < value.length(); cntr++) {
0922: char c = value.charAt(cntr);
0923:
0924: if (c == '\\') {
0925: char next = value.charAt(cntr + 1);
0926:
0927: switch (next) {
0928: case '0':
0929: case '1':
0930: case '2':
0931: case '3':
0932: case '4':
0933: case '5':
0934: case '6':
0935: case '7':
0936: case '8':
0937: case '9':
0938: result.append((char) Integer.parseInt(value
0939: .substring(cntr + 1, cntr + 5), 16));
0940: cntr += 4;
0941: break;
0942: case 'a':
0943: result.append('@');
0944: cntr++;
0945: break;
0946: case 'b':
0947: result.append(';');
0948: cntr++;
0949: break;
0950: case '\\':
0951: result.append('\\');
0952: cntr++;
0953: break;
0954: default:
0955: throw new IllegalStateException(
0956: "Unsupported escape: " + next);
0957: }
0958: } else {
0959: result.append(c);
0960: }
0961: }
0962:
0963: return result.toString();
0964: }
0965:
0966: private Object readConstantField(Reader r) throws IOException {
0967: Object result = null;
0968: int read = r.read();
0969:
0970: switch (read) {
0971: case 'Z':
0972: result = Boolean.parseBoolean(readPlainName(r)) ? Integer
0973: .valueOf(1) : Integer.valueOf(0);
0974: break;
0975: case 'B':
0976: result = Integer.valueOf(readPlainName(r));
0977: break;
0978: case 'S':
0979: result = Integer.valueOf(readPlainName(r));
0980: break;
0981: case 'I':
0982: result = Integer.valueOf(readPlainName(r));
0983: break;
0984: case 'J':
0985: result = Long.valueOf(readPlainName(r));
0986: break;
0987: case 'C':
0988: result = new Integer(Character.valueOf(readEscapedString(r)
0989: .charAt(0)));
0990: break;
0991: case 'F':
0992: result = Float.valueOf(readPlainName(r));
0993: break;
0994: case 'D':
0995: result = Double.valueOf(readPlainName(r));
0996: break;
0997: case 'L':
0998: result = readEscapedString(r);
0999: break;
1000: case 'X':
1001: read = r.read();
1002:
1003: assert read == ';';
1004: break;
1005: default:
1006: throw badClassFile("Unknown constant type: " + (char) read); //TODO: key!
1007: }
1008:
1009: return result;
1010: }
1011:
1012: private void attachAnnotations(Symbol sym, Reader r)
1013: throws IOException {
1014: List<CompoundAnnotationProxy> annotations = readAnnotations(r);
1015:
1016: if (!annotations.isEmpty()) {
1017: annotate.later(new AnnotationCompleter(sym, annotations));
1018: }
1019: }
1020:
1021: private List<CompoundAnnotationProxy> readAnnotations(Reader r)
1022: throws IOException {
1023: List<CompoundAnnotationProxy> attributes = List.nil();
1024: int read;
1025:
1026: while ((read = r.read()) != ';') {
1027: attributes = attributes.prepend(readAnnotation(r, read));
1028: }
1029:
1030: return attributes.reverse();
1031: }
1032:
1033: private CompoundAnnotationProxy readAnnotation(Reader r, int read)
1034: throws IOException {
1035: Type annotationType = readType(r, read);
1036:
1037: ListBuffer<Pair<Name, Attribute>> values = new ListBuffer<Pair<Name, Attribute>>();
1038:
1039: while ((read = r.read()) != ';') {
1040: assert read == 'N';
1041:
1042: Name attributeName = readPlainNameIntoTable(r);
1043:
1044: Attribute a = readAnnotationValue(r, r.read());
1045: values = values.append(new Pair<Name, Attribute>(
1046: attributeName, a));
1047: }
1048:
1049: return new CompoundAnnotationProxy(annotationType, values
1050: .toList());
1051: }
1052:
1053: private Attribute readEnum(Reader r) throws IOException {
1054: Type enumType = readType(r, r.read());
1055: Name constantName = readNameIntoTable(r);
1056: VarSymbol constant = null;
1057:
1058: for (Scope.Entry e = ((ClassType) enumType).tsym.members()
1059: .lookup(constantName); e.scope != null; e = e.next()) {
1060: if (e.sym.kind == VAR) {
1061: constant = (VarSymbol) e.sym;
1062: break;
1063: }
1064: }
1065: if (constant == null) {
1066: logger.error("unknown.enum.constant", currentClassFile,
1067: enumType, constant);
1068: return new Attribute.Error(enumType);
1069: } else {
1070: return new Attribute.Enum(enumType, constant);
1071: }
1072: }
1073:
1074: private Attribute readAnnotationValue(Reader r, int read)
1075: throws IOException {
1076: switch (read) {
1077: case 'Z':
1078: return new Attribute.Constant(syms.booleanType, Boolean
1079: .parseBoolean(readPlainName(r)) ? Integer
1080: .valueOf(1) : Integer.valueOf(0));
1081: case 'B':
1082: return new Attribute.Constant(syms.byteType, Integer
1083: .parseInt(readPlainName(r)));
1084: case 'S':
1085: return new Attribute.Constant(syms.shortType, Integer
1086: .parseInt(readPlainName(r)));
1087: case 'I':
1088: return new Attribute.Constant(syms.intType, Integer
1089: .parseInt(readPlainName(r)));
1090: case 'J':
1091: return new Attribute.Constant(syms.longType, Long
1092: .parseLong(readPlainName(r)));
1093: case 'C':
1094: return new Attribute.Constant(syms.charType, Integer
1095: .valueOf(Character.valueOf(readEscapedString(r)
1096: .charAt(0))));
1097: case 'F':
1098: return new Attribute.Constant(syms.floatType, Float
1099: .parseFloat(readPlainName(r)));
1100: case 'D':
1101: return new Attribute.Constant(syms.doubleType, Double
1102: .parseDouble(readPlainName(r)));
1103: case 'L':
1104: return new Attribute.Constant(syms.stringType,
1105: readEscapedString(r));
1106: case 'O':
1107: return new EnumAttributeProxy(readType(r, r.read()),
1108: readNameIntoTable(r));
1109: case 'P':
1110: return readAnnotation(r, r.read());
1111: case '[':
1112: ListBuffer<Attribute> items = new ListBuffer<Attribute>();
1113:
1114: while ((read = r.read()) != ';') {
1115: items.append(readAnnotationValue(r, read));
1116: }
1117:
1118: return new ArrayAttributeProxy(items.toList());
1119: case 'Y':
1120: return new Attribute.Class(types, readType(r, r.read()));
1121: }
1122:
1123: throw new IllegalStateException("Completing: "
1124: + ((ClassSymbol) currentOwner).flatname.toString()
1125: + ", read=" + ((char) read) + ":" + read);
1126: }
1127:
1128: //for tests:
1129: protected @Override
1130: void includeClassFile(PackageSymbol p, JavaFileObject file,
1131: String binaryName) {
1132: super.includeClassFile(p, file, binaryName);
1133: }
1134:
1135: }
|