# HG changeset patch # User mcimadamore # Date 1222685289 -3600 # Node ID e2d4f3e1f8059487941db2b5d45ce3f85c546453 # Parent 9f40f16e543b75039ad4be6897cb9ba756152a24 6735840: Need a type/symbol visitor printer Summary: Added type/symbol visitor printer with support for localization Reviewed-by: jjg diff -r 9f40f16e543b -r e2d4f3e1f805 langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java --- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Mon Sep 29 11:34:43 2008 +0100 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Mon Sep 29 11:48:09 2008 +0100 @@ -132,6 +132,10 @@ throw new AssertionError(); } + public R accept(Symbol.Visitor v, P p) { + return v.visitSymbol(this, p); + } + /** The Java source which this symbol represents. * A description of this symbol; overrides Object. */ @@ -477,6 +481,10 @@ public R accept(ElementVisitor v, P p) { return other.accept(v, p); } + + public R accept(Symbol.Visitor v, P p) { + return v.visitSymbol(other, p); + } } /** A class for type symbols. Type variables are represented by instances @@ -570,6 +578,10 @@ return v.visitTypeParameter(this, p); } + public R accept(Symbol.Visitor v, P p) { + return v.visitTypeSymbol(this, p); + } + public List getBounds() { TypeVar t = (TypeVar)type; Type bound = t.getUpperBound(); @@ -653,6 +665,10 @@ public R accept(ElementVisitor v, P p) { return v.visitPackage(this, p); } + + public R accept(Symbol.Visitor v, P p) { + return v.visitPackageSymbol(this, p); + } } /** A class for class symbols @@ -843,6 +859,10 @@ public R accept(ElementVisitor v, P p) { return v.visitType(this, p); } + + public R accept(Symbol.Visitor v, P p) { + return v.visitClassSymbol(this, p); + } } @@ -969,6 +989,10 @@ assert !(data instanceof Env) : this; this.data = data; } + + public R accept(Symbol.Visitor v, P p) { + return v.visitVarSymbol(this, p); + } } /** A class for method symbols. @@ -1232,6 +1256,10 @@ return v.visitExecutable(this, p); } + public R accept(Symbol.Visitor v, P p) { + return v.visitMethodSymbol(this, p); + } + public Type getReturnType() { return asType().getReturnType(); } @@ -1251,6 +1279,10 @@ super(PUBLIC | STATIC, name, type, owner); this.opcode = opcode; } + + public R accept(Symbol.Visitor v, P p) { + return v.visitOperatorSymbol(this, p); + } } /** Symbol completer interface. @@ -1308,4 +1340,28 @@ } } + + /** + * A visitor for symbols. A visitor is used to implement operations + * (or relations) on symbols. Most common operations on types are + * binary relations and this interface is designed for binary + * relations, that is, operations on the form + * Symbol × P → R. + * + * + * @param the return type of the operation implemented by this + * visitor; use Void if no return type is needed. + * @param

the type of the second argument (the first being the + * symbol itself) of the operation implemented by this visitor; use + * Void if a second argument is not needed. + */ + public interface Visitor { + R visitClassSymbol(ClassSymbol s, P arg); + R visitMethodSymbol(MethodSymbol s, P arg); + R visitPackageSymbol(PackageSymbol s, P arg); + R visitOperatorSymbol(OperatorSymbol s, P arg); + R visitVarSymbol(VarSymbol s, P arg); + R visitTypeSymbol(TypeSymbol s, P arg); + R visitSymbol(Symbol s, P arg); + } } diff -r 9f40f16e543b -r e2d4f3e1f805 langtools/src/share/classes/com/sun/tools/javac/code/Types.java --- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Mon Sep 29 11:34:43 2008 +0100 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Mon Sep 29 11:48:09 2008 +0100 @@ -67,6 +67,7 @@ new Context.Key(); final Symtab syms; + final Messages messages; final Names names; final boolean allowBoxing; final ClassReader reader; @@ -92,6 +93,7 @@ source = Source.instance(context); chk = Check.instance(context); capturedName = names.fromString(""); + messages = Messages.instance(context); } // @@ -1589,10 +1591,10 @@ syms.noSymbol); if (bounds.head.tag == TYPEVAR) // error condition, recover - bc.erasure_field = syms.objectType; - else - bc.erasure_field = erasure(bounds.head); - bc.members_field = new Scope(bc); + bc.erasure_field = syms.objectType; + else + bc.erasure_field = erasure(bounds.head); + bc.members_field = new Scope(bc); ClassType bt = (ClassType)bc.type; bt.allparams_field = List.nil(); if (supertype != null) { @@ -2249,10 +2251,234 @@ } // + // + /** + * Visitor for generating a string representation of a given type + * accordingly to a given locale + */ + public String toString(Type t, Locale locale) { + return typePrinter.visit(t, locale); + } + // where + private TypePrinter typePrinter = new TypePrinter(); + + public class TypePrinter extends DefaultTypeVisitor { + + public String visit(List ts, Locale locale) { + ListBuffer sbuf = lb(); + for (Type t : ts) { + sbuf.append(visit(t, locale)); + } + return sbuf.toList().toString(); + } + + @Override + public String visitCapturedType(CapturedType t, Locale locale) { + return messages.getLocalizedString("compiler.misc.type.captureof", + (t.hashCode() & 0xFFFFFFFFL) % Type.CapturedType.PRIME, + visit(t.wildcard, locale)); + } + + @Override + public String visitForAll(ForAll t, Locale locale) { + return "<" + visit(t.tvars, locale) + ">" + visit(t.qtype, locale); + } + + @Override + public String visitUndetVar(UndetVar t, Locale locale) { + if (t.inst != null) { + return visit(t.inst, locale); + } else { + return visit(t.qtype, locale) + "?"; + } + } + + @Override + public String visitArrayType(ArrayType t, Locale locale) { + return visit(t.elemtype, locale) + "[]"; + } + + @Override + public String visitClassType(ClassType t, Locale locale) { + StringBuffer buf = new StringBuffer(); + if (t.getEnclosingType().tag == CLASS && t.tsym.owner.kind == Kinds.TYP) { + buf.append(visit(t.getEnclosingType(), locale)); + buf.append("."); + buf.append(className(t, false, locale)); + } else { + buf.append(className(t, true, locale)); + } + if (t.getTypeArguments().nonEmpty()) { + buf.append('<'); + buf.append(visit(t.getTypeArguments(), locale)); + buf.append(">"); + } + return buf.toString(); + } + + @Override + public String visitMethodType(MethodType t, Locale locale) { + return "(" + printMethodArgs(t.argtypes, false, locale) + ")" + visit(t.restype, locale); + } + + @Override + public String visitPackageType(PackageType t, Locale locale) { + return t.tsym.getQualifiedName().toString(); + } + + @Override + public String visitWildcardType(WildcardType t, Locale locale) { + StringBuffer s = new StringBuffer(); + s.append(t.kind); + if (t.kind != UNBOUND) { + s.append(visit(t.type, locale)); + } + return s.toString(); + } + + + public String visitType(Type t, Locale locale) { + String s = (t.tsym == null || t.tsym.name == null) + ? messages.getLocalizedString("compiler.misc.type.none") + : t.tsym.name.toString(); + return s; + } + + protected String className(ClassType t, boolean longform, Locale locale) { + Symbol sym = t.tsym; + if (sym.name.length() == 0 && (sym.flags() & COMPOUND) != 0) { + StringBuffer s = new StringBuffer(visit(supertype(t), locale)); + for (List is = interfaces(t); is.nonEmpty(); is = is.tail) { + s.append("&"); + s.append(visit(is.head, locale)); + } + return s.toString(); + } else if (sym.name.length() == 0) { + String s; + ClassType norm = (ClassType) t.tsym.type; + if (norm == null) { + s = getLocalizedString(locale, "compiler.misc.anonymous.class", (Object) null); + } else if (interfaces(norm).nonEmpty()) { + s = getLocalizedString(locale, "compiler.misc.anonymous.class", + visit(interfaces(norm).head, locale)); + } else { + s = getLocalizedString(locale, "compiler.misc.anonymous.class", + visit(supertype(norm), locale)); + } + return s; + } else if (longform) { + return sym.getQualifiedName().toString(); + } else { + return sym.name.toString(); + } + } + + protected String printMethodArgs(List args, boolean varArgs, Locale locale) { + if (!varArgs) { + return visit(args, locale); + } else { + StringBuffer buf = new StringBuffer(); + while (args.tail.nonEmpty()) { + buf.append(visit(args.head, locale)); + args = args.tail; + buf.append(','); + } + if (args.head.tag == ARRAY) { + buf.append(visit(((ArrayType) args.head).elemtype, locale)); + buf.append("..."); + } else { + buf.append(visit(args.head, locale)); + } + return buf.toString(); + } + } + + protected String getLocalizedString(Locale locale, String key, Object... args) { + return messages.getLocalizedString(key, args); + } + }; + // + + // + /** + * Visitor for generating a string representation of a given symbol + * accordingly to a given locale + */ + public String toString(Symbol t, Locale locale) { + return symbolPrinter.visit(t, locale); + } + // where + private SymbolPrinter symbolPrinter = new SymbolPrinter(); + + public class SymbolPrinter extends DefaultSymbolVisitor { + + @Override + public String visitClassSymbol(ClassSymbol sym, Locale locale) { + return sym.name.isEmpty() + ? getLocalizedString(locale, "compiler.misc.anonymous.class", sym.flatname) + : sym.fullname.toString(); + } + + @Override + public String visitMethodSymbol(MethodSymbol s, Locale locale) { + if ((s.flags() & BLOCK) != 0) { + return s.owner.name.toString(); + } else { + String ms = (s.name == names.init) + ? s.owner.name.toString() + : s.name.toString(); + if (s.type != null) { + if (s.type.tag == FORALL) { + ms = "<" + typePrinter.visit(s.type.getTypeArguments(), locale) + ">" + ms; + } + ms += "(" + typePrinter.printMethodArgs( + s.type.getParameterTypes(), + (s.flags() & VARARGS) != 0, + locale) + ")"; + } + return ms; + } + } + + @Override + public String visitOperatorSymbol(OperatorSymbol s, Locale locale) { + return visitMethodSymbol(s, locale); + } + + @Override + public String visitPackageSymbol(PackageSymbol s, Locale locale) { + return s.name.isEmpty() + ? getLocalizedString(locale, "compiler.misc.unnamed.package") + : s.fullname.toString(); + } + + @Override + public String visitSymbol(Symbol s, Locale locale) { + return s.name.toString(); + } + + public String visit(List ts, Locale locale) { + ListBuffer sbuf = lb(); + for (Symbol t : ts) { + sbuf.append(visit(t, locale)); + } + return sbuf.toList().toString(); + } + + protected String getLocalizedString(Locale locale, String key, Object... args) { + return messages.getLocalizedString(key, args); + } + }; + // + // /** * This toString is slightly more descriptive than the one on Type. + * + * @deprecated Types.toString(Type t, Locale l) provides better support + * for localization */ + @Deprecated public String toString(Type t) { if (t.tag == FORALL) { ForAll forAll = (ForAll)t; @@ -3236,6 +3462,28 @@ } /** + * A default visitor for symbols. All visitor methods except + * visitSymbol are implemented by delegating to visitSymbol. Concrete + * subclasses must provide an implementation of visitSymbol and can + * override other methods as needed. + * + * @param the return type of the operation implemented by this + * visitor; use Void if no return type is needed. + * @param the type of the second argument (the first being the + * symbol itself) of the operation implemented by this visitor; use + * Void if a second argument is not needed. + */ + public static abstract class DefaultSymbolVisitor implements Symbol.Visitor { + final public R visit(Symbol s, S arg) { return s.accept(this, arg); } + public R visitClassSymbol(ClassSymbol s, S arg) { return visitSymbol(s, arg); } + public R visitMethodSymbol(MethodSymbol s, S arg) { return visitSymbol(s, arg); } + public R visitOperatorSymbol(OperatorSymbol s, S arg) { return visitSymbol(s, arg); } + public R visitPackageSymbol(PackageSymbol s, S arg) { return visitSymbol(s, arg); } + public R visitTypeSymbol(TypeSymbol s, S arg) { return visitSymbol(s, arg); } + public R visitVarSymbol(VarSymbol s, S arg) { return visitSymbol(s, arg); } + } + + /** * A simple visitor for types. This visitor is simple as * captured wildcards, for-all types (generic methods), and * undetermined type variables (part of inference) are hidden. diff -r 9f40f16e543b -r e2d4f3e1f805 langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties --- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Sep 29 11:34:43 2008 +0100 +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Sep 29 11:48:09 2008 +0100 @@ -823,6 +823,12 @@ compiler.misc.anonymous.class=\ +compiler.misc.type.captureof=\ + capture#{0} of {1} + +compiler.misc.type.none=\ + + compiler.misc.unnamed.package=\ unnamed package