/* * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package org.visage.tools.comp; import java.util.IdentityHashMap; import java.util.Set; import java.util.HashSet; import javax.tools.JavaFileObject; import com.sun.tools.mjavac.jvm.ClassReader; import com.sun.tools.mjavac.code.*; import com.sun.tools.mjavac.code.Type.*; import com.sun.tools.mjavac.code.Symbol.*; import com.sun.tools.mjavac.util.*; import com.sun.tools.mjavac.util.List; import static com.sun.tools.mjavac.code.Flags.*; import static com.sun.tools.mjavac.code.Kinds.*; import static com.sun.tools.mjavac.code.TypeTags.*; import org.visage.tools.code.VisageClassSymbol; import org.visage.tools.code.VisageSymtab; import org.visage.tools.code.VisageFlags; import org.visage.tools.code.VisageTypes; import org.visage.tools.code.VisageVarSymbol; import org.visage.tools.tree.VisageTreeMaker; import org.visage.tools.util.MsgSym; import org.visage.tools.main.VisageCompiler; /** Provides operations to read a classfile into an internal * representation. The internal representation is anchored in a * VisageClassSymbol which contains in its scope symbol representations * for all other definitions in the classfile. Top-level Classes themselves * appear as members of the scopes of PackageSymbols. * * We delegate actual classfile-reading to javac's ClassReader, and then * translates the resulting ClassSymbol to VisageClassSymbol, doing some * renaming etc to make the resulting Symbols and Types match those produced * by the parser. This munging is incomplete, and there are still places * where the compiler needs to know if a class comes from the parser or a * classfile; those places will hopefully become fewer. * * <p><b>This is NOT part of any API supported by Sun Microsystems. If * you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice.</b> */ public class VisageClassReader extends ClassReader { protected static final Context.Key<ClassReader> backendClassReaderKey = new Context.Key<ClassReader>(); private final VisageDefs defs; protected final VisageTypes visageTypes; protected final VisageTreeMaker visagemake; /** The raw class-reader, shared by the back-end. */ public ClassReader jreader; private final Name functionClassPrefixName; private Context ctx; private Messages messages; public static void preRegister(final Context context, final ClassReader jreader) { context.put(backendClassReaderKey, jreader); Object instance = context.get(classReaderKey); if (instance instanceof VisageClassReader) ((VisageClassReader) instance).jreader = jreader; else preRegister(context); } public static void preRegister(final Context context) { context.put(classReaderKey, new Context.Factory<ClassReader>() { public VisageClassReader make() { VisageClassReader reader = new VisageClassReader(context, true); reader.jreader = context.get(backendClassReaderKey); return reader; } }); } public static VisageClassReader instance(Context context) { VisageClassReader instance = (VisageClassReader) context.get(classReaderKey); if (instance == null) instance = new VisageClassReader(context, true); return instance; } /** Construct a new class reader, optionally treated as the * definitive classreader for this invocation. */ protected VisageClassReader(Context context, boolean definitive) { super(context, definitive); defs = VisageDefs.instance(context); visageTypes = VisageTypes.instance(context); visagemake = VisageTreeMaker.instance(context); functionClassPrefixName = names.fromString(VisageSymtab.functionClassPrefix); ctx = context; messages = Messages.instance(context); } public Name.Table getNames() { return names; } /** Reassign names of classes that might have been loaded with * their flat names. */ void fixupFullname (VisageClassSymbol cSym, ClassSymbol jsymbol) { if (cSym.fullname != jsymbol.fullname && cSym.owner.kind == PCK && jsymbol.owner.kind == TYP) { cSym.owner.members().remove(cSym); cSym.name = jsymbol.name; ClassSymbol owner = enterClass(((ClassSymbol) jsymbol.owner).flatname); cSym.owner = owner; cSym.fullname = ClassSymbol.formFullName(cSym.name, owner); } } public VisageClassSymbol enterClass(ClassSymbol jsymbol) { Name className = jsymbol.flatname; boolean mixin = className.endsWith(defs.mixinClassSuffixName); if (mixin) className = className.subName(0, className.len - defs.mixinClassSuffixName.len); VisageClassSymbol cSym = (VisageClassSymbol) enterClass(className); //cSym.flags_field |= jsymbol.flags_field; if (mixin) cSym.flags_field |= VisageFlags.MIXIN; else { fixupFullname(cSym, jsymbol); cSym.jsymbol = jsymbol; } return cSym; } /** Define a new class given its name and owner. */ @Override public ClassSymbol defineClass(Name name, Symbol owner) { ClassSymbol c = new VisageClassSymbol(0, name, owner); if (owner.kind == PCK) assert classes.get(c.flatname) == null : c; c.completer = this; return c; } /* FIXME: The re-written class-reader doesn't translate annotations yet. protected void attachAnnotations(final Symbol sym) { int numAttributes = nextChar(); if (numAttributes != 0) { ListBuffer<CompoundAnnotationProxy> proxies = new ListBuffer<CompoundAnnotationProxy>(); for (int i = 0; i<numAttributes; i++) { CompoundAnnotationProxy proxy = readCompoundAnnotation(); if (proxy.type.tsym == syms.proprietaryType.tsym) sym.flags_field |= PROPRIETARY; else { proxies.append(proxy); } } annotate.later(new VisageAnnotationCompleter(sym, proxies.toList(), this)); } } static public class VisageAnnotationCompleter extends AnnotationCompleter { VisageClassReader classReader; public VisageAnnotationCompleter(Symbol sym, List<CompoundAnnotationProxy> l, ClassReader classReader) { super(sym, l, classReader); this.classReader = (VisageClassReader)classReader; } // implement Annotate.Annotator.enterAnnotation() public void enterAnnotation() { JavaFileObject previousClassFile = classReader.currentClassFile; try { classReader.currentClassFile = classFile; List<Attribute.Compound> newList = deproxyCompoundList(l); VisageSymtab visageSyms = (VisageSymtab)classReader.syms; for (Attribute.Compound comp : newList) { } sym.attributes_field = ((sym.attributes_field == null) ? newList : newList.prependList(sym.attributes_field)); } finally { classReader.currentClassFile = previousClassFile; } } } */ /** Map javac Type/Symbol to visage Type/Symbol. */ IdentityHashMap<Object,Object> typeMap = new IdentityHashMap<Object,Object>(); /** Translate a List of raw JVM types to Visage types. */ List<Type> translateTypes (List<Type> types) { if (types == null) return null; List<Type> ts = (List<Type>) typeMap.get(types); if (ts != null) return ts; ListBuffer<Type> rs = new ListBuffer<Type>(); for (List<Type> t = types; t.tail != null; t = t.tail) rs.append(translateType(t.head)); ts = rs.toList(); typeMap.put(types, ts); return ts; } /** Translate raw JVM type to Visage type. */ Type translateType (Type type) { if (type == null) return null; Type t = (Type) typeMap.get(type); if (t != null) return t; switch (type.tag) { case VOID: t = syms.voidType; break; case BOOLEAN: t = syms.booleanType; break; case CHAR: t = syms.charType; break; case BYTE: t = syms.byteType; break; case SHORT: t = syms.shortType; break; case INT: t = syms.intType; break; case LONG: t = syms.longType; break; case DOUBLE: t = syms.doubleType; break; case FLOAT: t = syms.floatType; break; case TYPEVAR: TypeVar tv = (TypeVar) type; TypeVar tx = new TypeVar(null, (Type) null, (Type) null); typeMap.put(type, tx); // In case of a cycle. tx.bound = translateType(tv.bound); tx.lower = translateType(tv.lower); tx.tsym = new TypeSymbol(0, tv.tsym.name, tx, translateSymbol(tv.tsym.owner)); return tx; case FORALL: ForAll tf = (ForAll) type; t = new ForAll(translateTypes(tf.tvars), translateType(tf.qtype)); break; case WILDCARD: WildcardType wt = (WildcardType) type; t = new WildcardType(translateType(wt.type), wt.kind, translateTypeSymbol(wt.tsym)); break; case CLASS: TypeSymbol tsym = type.tsym; if (tsym instanceof ClassSymbol) { if (tsym.name.endsWith(defs.mixinClassSuffixName)) { t = enterClass((ClassSymbol) tsym).type; break; } final ClassType ctype = (ClassType) type; if (ctype.isCompound()) { t = types.makeCompoundType(translateTypes(ctype.interfaces_field), translateType(ctype.supertype_field)); break; } Name flatname = ((ClassSymbol) tsym).flatname; if (flatname.startsWith(functionClassPrefixName) && flatname != functionClassPrefixName) { t = ((VisageSymtab) syms).makeFunctionType(translateTypes(ctype.typarams_field)); break; } TypeSymbol sym = translateTypeSymbol(tsym); ClassType ntype; if (tsym.type == type) ntype = (ClassType) sym.type; else ntype = new ClassType(Type.noType, List.<Type>nil(), sym) { boolean completed = false; @Override public Type getEnclosingType() { if (!completed) { completed = true; tsym.complete(); super.setEnclosingType(translateType(ctype.getEnclosingType())); } return super.getEnclosingType(); } @Override public void setEnclosingType(Type outer) { throw new UnsupportedOperationException(); } @Override public boolean equals(Object t) { return super.equals(t); } @Override public int hashCode() { return super.hashCode(); } }; typeMap.put(type, ntype); // In case of a cycle. ntype.typarams_field = translateTypes(type.getTypeArguments()); return ntype; } break; case ARRAY: t = new ArrayType(translateType(((ArrayType) type).elemtype), syms.arrayClass); break; case METHOD: t = new MethodType(translateTypes(type.getParameterTypes()), translateType(type.getReturnType()), translateTypes(type.getThrownTypes()), syms.methodClass); break; default: t = type; // FIXME } typeMap.put(type, t); return t; } TypeSymbol translateTypeSymbol(TypeSymbol tsym) { if (tsym == syms.predefClass) return tsym; ClassSymbol csym = (ClassSymbol) tsym; // FIXME return enterClass(csym); } Symbol translateSymbol(Symbol sym) { if (sym == null) return null; Symbol s = (Symbol) typeMap.get(sym); if (s != null) return s; if (sym instanceof PackageSymbol) s = enterPackage(((PackageSymbol) sym).fullname); else if (sym instanceof MethodSymbol) { Symbol owner = translateSymbol(sym.owner); MethodSymbol m = translateMethodSymbol(sym.flags_field, sym, owner); ((ClassSymbol) owner).members_field.enter(m); s = m; } else s = translateTypeSymbol((TypeSymbol) sym); typeMap.put(sym, s); return s; } void popMethodTypeArg(MethodType type) { List<Type> argtypes = type.argtypes; ListBuffer<Type> lb = ListBuffer.<Type>lb(); for (int i = 1; i < argtypes.size(); i++) { lb.append(argtypes.get(i)); } type.argtypes = lb.toList(); } MethodSymbol translateMethodSymbol(long flags, Symbol sym, Symbol owner) { Name name = sym.name; Type mtype = sym.type; String nameString = name.toString(); int boundStringIndex = nameString.indexOf(VisageDefs.boundFunctionDollarSuffix); if (boundStringIndex != -1) { // this is a bound function // remove the bound suffix, and mark as bound nameString = nameString.substring(0, boundStringIndex); flags |= VisageFlags.BOUND; } VisageSymtab visageSyms = (VisageSymtab) this.syms; for (Attribute.Compound ann : sym.getAnnotationMirrors()) { if (ann.type.tsym.flatName() == visageSyms.visage_signatureAnnotationType.tsym.flatName()) { String sig = (String)ann.values.head.snd.getValue(); signatureBuffer = new byte[sig.length()]; try { mtype = sigToType(names.fromString(sig)); } catch (Exception e) { throw new AssertionError("Bad Visage signature"); } } } Type type = translateType(mtype); if (type instanceof MethodType) { boolean convertToStatic = false; if (nameString.endsWith(VisageDefs.implFunctionSuffix)) { nameString = nameString.substring(0, nameString.length() - VisageDefs.implFunctionSuffix.length()); convertToStatic = true; } if (convertToStatic) { flags &= ~Flags.STATIC; popMethodTypeArg((MethodType)type); } } name = names.fromString(nameString); return new MethodSymbol(flags, name, type, owner); } // VSGC-2849 - Mixins: Change the mixin interface from $Intf to $Mixin. private void checkForIntfSymbol(Symbol sym) throws CompletionFailure { if (sym.name.endsWith(defs.deprecatedInterfaceSuffixName)) { String fileString = ((ClassSymbol) sym).classfile.getName(); String message = messages.getLocalizedString(MsgSym.MESSAGEPREFIX_COMPILER_MISC + MsgSym.MESSAGE_DEPRECATED_INTERFACE_CLASS, fileString); log.rawError(Position.NOPOS, message); throw new CompletionFailure(sym, message); } } @Override public void complete(Symbol sym) throws CompletionFailure { checkForIntfSymbol(sym); if (jreader.sourceCompleter == null) jreader.sourceCompleter = VisageCompiler.instance(ctx); if (sym instanceof PackageSymbol) { PackageSymbol psym = (PackageSymbol) sym; PackageSymbol jpackage; if (psym == syms.unnamedPackage) jpackage = jreader.syms.unnamedPackage; else jpackage = jreader.enterPackage(psym.fullname); jpackage.complete(); if (psym.members_field == null) psym.members_field = new Scope(psym); for (Scope.Entry e = jpackage.members_field.elems; e != null; e = e.sibling) { if (e.sym instanceof ClassSymbol) { ClassSymbol jsym = (ClassSymbol) e.sym; if (jsym.name.endsWith(defs.mixinClassSuffixName)) continue; VisageClassSymbol csym = enterClass(jsym); psym.members_field.enter(csym); csym.classfile = jsym.classfile; csym.jsymbol = jsym; } } if (jpackage.exists()) psym.flags_field |= EXISTS; } else { sym.owner.complete(); VisageClassSymbol csym = (VisageClassSymbol) sym; ClassSymbol jsymbol = csym.jsymbol; if (jsymbol != null && jsymbol.classfile != null && jsymbol.classfile.getKind() == JavaFileObject.Kind.SOURCE && jsymbol.classfile.getName().endsWith(".visage")) { SourceCompleter visageSourceCompleter = VisageCompiler.instance(ctx); visageSourceCompleter.complete(csym); return; } else { csym.jsymbol = jsymbol = jreader.loadClass(csym.flatname); } fixupFullname(csym, jsymbol); typeMap.put(jsymbol, csym); jsymbol.classfile = ((ClassSymbol) sym).classfile; ClassType ct = (ClassType)csym.type; ClassType jt = (ClassType)jsymbol.type; csym.members_field = new Scope(csym); // flags are derived from flag bits and access modifier annoations csym.flags_field = flagsFromAnnotationsAndFlags(jsymbol); ct.typarams_field = translateTypes(jt.typarams_field); ct.setEnclosingType(translateType(jt.getEnclosingType())); ct.supertype_field = translateType(jt.supertype_field); // VSGC-2841 - Mixins: Cannot find firePropertyChange method in SwingComboBox.visage if (ct.supertype_field != null && ct.supertype_field.tsym != null && ct.supertype_field.tsym.kind == TYP) { } ListBuffer<Type> interfaces = new ListBuffer<Type>(); Type iface = null; if (jt.interfaces_field != null) { // true for ErrorType for (List<Type> it = jt.interfaces_field; it.tail != null; it = it.tail) { Type itype = it.head; checkForIntfSymbol(itype.tsym); if (((ClassSymbol) itype.tsym).flatname == defs.cObjectName) { csym.flags_field |= VisageFlags.VISAGE_CLASS; } else if (((ClassSymbol) itype.tsym).flatname == defs.cMixinName) { csym.flags_field |= VisageFlags.MIXIN | VisageFlags.VISAGE_CLASS; } else if ((csym.fullname.len + defs.mixinClassSuffixName.len == ((ClassSymbol) itype.tsym).fullname.len) && ((ClassSymbol) itype.tsym).fullname.startsWith(csym.fullname) && itype.tsym.name.endsWith(defs.mixinClassSuffixName)) { iface = itype; iface.tsym.complete(); csym.flags_field |= VisageFlags.MIXIN | VisageFlags.VISAGE_CLASS; } else { itype = translateType(itype); interfaces.append(itype); } } } if (iface != null) { for (List<Type> it = ((ClassType) iface.tsym.type).interfaces_field; it.tail != null; it = it.tail) { Type itype = it.head; checkForIntfSymbol(itype.tsym); if (((ClassSymbol) itype.tsym).flatname == defs.cObjectName) { csym.flags_field |= VisageFlags.VISAGE_CLASS; } else if (((ClassSymbol) itype.tsym).flatname == defs.cMixinName) { csym.flags_field |= VisageFlags.MIXIN | VisageFlags.VISAGE_CLASS; } else { itype = translateType(itype); interfaces.append(itype); } } } ct.interfaces_field = interfaces.toList(); // Now translate the members. // Do an initial "reverse" pass so we copy the order. List<Symbol> symlist = List.nil(); for (Scope.Entry e = jsymbol.members_field.elems; e != null; e = e.sibling) { if ((e.sym.flags_field & SYNTHETIC) != 0) continue; symlist = symlist.prepend(e.sym); } boolean isVisageClass = (csym.flags_field & VisageFlags.VISAGE_CLASS) != 0; boolean isMixinClass = (csym.flags_field & VisageFlags.MIXIN) != 0; VisageVarSymbol scriptAccessSymbol = isVisageClass ? visagemake.ScriptAccessSymbol(csym) : null; Set<Name> priorNames = new HashSet<Name>(); handleSyms: for (List<Symbol> l = symlist; l.nonEmpty(); l=l.tail) { Symbol memsym = l.head; Name name = memsym.name; long flags = flagsFromAnnotationsAndFlags(memsym); if ((flags & PRIVATE) != 0) continue; boolean sawSourceNameAnnotation = false; VisageSymtab visageSyms = (VisageSymtab) this.syms; for (Attribute.Compound a : memsym.getAnnotationMirrors()) { if (a.type.tsym.flatName() == visageSyms.visage_staticAnnotationType.tsym.flatName()) { flags |= Flags.STATIC; } else if (a.type.tsym.flatName() == visageSyms.visage_defAnnotationType.tsym.flatName()) { flags |= VisageFlags.IS_DEF; } else if (a.type.tsym.flatName() == visageSyms.visage_defaultAnnotationType.tsym.flatName()) { flags |= VisageFlags.DEFAULT; } else if (a.type.tsym.flatName() == visageSyms.visage_publicInitAnnotationType.tsym.flatName()) { flags |= VisageFlags.PUBLIC_INIT; } else if (a.type.tsym.flatName() == visageSyms.visage_publicReadAnnotationType.tsym.flatName()) { flags |= VisageFlags.PUBLIC_READ; } else if (a.type.tsym.flatName() == visageSyms.visage_inheritedAnnotationType.tsym.flatName()) { continue handleSyms; } else if (a.type.tsym.flatName() == visageSyms.visage_sourceNameAnnotationType.tsym.flatName()) { Attribute aa = a.member(name.table.value); Object sourceName = aa.getValue(); if (sourceName instanceof String) { name = names.fromString((String) sourceName); sawSourceNameAnnotation = true; } } } if (memsym instanceof MethodSymbol) { MethodSymbol m = translateMethodSymbol(flags, memsym, csym); csym.members_field.enter(m); } else if (memsym instanceof VarSymbol) { // Eliminate any duplicate value/location. if (priorNames.contains(name)) continue; Type otype = memsym.type; Type type = translateType(otype); VisageVarSymbol v; if (scriptAccessSymbol != null && name == scriptAccessSymbol.name) { v = scriptAccessSymbol; } else { v = new VisageVarSymbol(visageTypes, names, flags, name, type, csym); csym.addVar(v, (flags & STATIC) != 0); } csym.members_field.enter(v); if ((flags & VisageFlags.DEFAULT) != 0) { csym.setDefaultVar(name); } priorNames.add(name); } else { memsym.flags_field = flags; csym.members_field.enter(translateSymbol(memsym)); } } } } private long flagsFromAnnotationsAndFlags(Symbol sym) { long initialFlags = sym.flags_field; long nonAccessFlags = initialFlags & ~VisageFlags.VisageAccessFlags; long accessFlags = initialFlags & VisageFlags.VisageAccessFlags; VisageSymtab visageSyms = (VisageSymtab) this.syms; for (Attribute.Compound a : sym.getAnnotationMirrors()) { if (a.type.tsym.flatName() == visageSyms.visage_protectedAnnotationType.tsym.flatName()) { accessFlags = Flags.PROTECTED; } else if (a.type.tsym.flatName() == visageSyms.visage_packageAnnotationType.tsym.flatName()) { accessFlags = 0L; } else if (a.type.tsym.flatName() == visageSyms.visage_publicAnnotationType.tsym.flatName()) { accessFlags = Flags.PUBLIC; } else if (a.type.tsym.flatName() == visageSyms.visage_scriptPrivateAnnotationType.tsym.flatName()) { accessFlags = VisageFlags.SCRIPT_PRIVATE; } } if (accessFlags == 0L) { accessFlags = VisageFlags.PACKAGE_ACCESS; } return nonAccessFlags | accessFlags; } }