Mon, 29 Sep 2008 11:48:09 +0100
6735840: Need a type/symbol visitor printer
Summary: Added type/symbol visitor printer with support for localization
Reviewed-by: jjg
1.1 --- a/src/share/classes/com/sun/tools/javac/code/Symbol.java Mon Sep 29 11:34:43 2008 +0100 1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Symbol.java Mon Sep 29 11:48:09 2008 +0100 1.3 @@ -132,6 +132,10 @@ 1.4 throw new AssertionError(); 1.5 } 1.6 1.7 + public <R, P> R accept(Symbol.Visitor<R, P> v, P p) { 1.8 + return v.visitSymbol(this, p); 1.9 + } 1.10 + 1.11 /** The Java source which this symbol represents. 1.12 * A description of this symbol; overrides Object. 1.13 */ 1.14 @@ -477,6 +481,10 @@ 1.15 public <R, P> R accept(ElementVisitor<R, P> v, P p) { 1.16 return other.accept(v, p); 1.17 } 1.18 + 1.19 + public <R, P> R accept(Symbol.Visitor<R, P> v, P p) { 1.20 + return v.visitSymbol(other, p); 1.21 + } 1.22 } 1.23 1.24 /** A class for type symbols. Type variables are represented by instances 1.25 @@ -570,6 +578,10 @@ 1.26 return v.visitTypeParameter(this, p); 1.27 } 1.28 1.29 + public <R, P> R accept(Symbol.Visitor<R, P> v, P p) { 1.30 + return v.visitTypeSymbol(this, p); 1.31 + } 1.32 + 1.33 public List<Type> getBounds() { 1.34 TypeVar t = (TypeVar)type; 1.35 Type bound = t.getUpperBound(); 1.36 @@ -653,6 +665,10 @@ 1.37 public <R, P> R accept(ElementVisitor<R, P> v, P p) { 1.38 return v.visitPackage(this, p); 1.39 } 1.40 + 1.41 + public <R, P> R accept(Symbol.Visitor<R, P> v, P p) { 1.42 + return v.visitPackageSymbol(this, p); 1.43 + } 1.44 } 1.45 1.46 /** A class for class symbols 1.47 @@ -843,6 +859,10 @@ 1.48 public <R, P> R accept(ElementVisitor<R, P> v, P p) { 1.49 return v.visitType(this, p); 1.50 } 1.51 + 1.52 + public <R, P> R accept(Symbol.Visitor<R, P> v, P p) { 1.53 + return v.visitClassSymbol(this, p); 1.54 + } 1.55 } 1.56 1.57 1.58 @@ -969,6 +989,10 @@ 1.59 assert !(data instanceof Env<?>) : this; 1.60 this.data = data; 1.61 } 1.62 + 1.63 + public <R, P> R accept(Symbol.Visitor<R, P> v, P p) { 1.64 + return v.visitVarSymbol(this, p); 1.65 + } 1.66 } 1.67 1.68 /** A class for method symbols. 1.69 @@ -1232,6 +1256,10 @@ 1.70 return v.visitExecutable(this, p); 1.71 } 1.72 1.73 + public <R, P> R accept(Symbol.Visitor<R, P> v, P p) { 1.74 + return v.visitMethodSymbol(this, p); 1.75 + } 1.76 + 1.77 public Type getReturnType() { 1.78 return asType().getReturnType(); 1.79 } 1.80 @@ -1251,6 +1279,10 @@ 1.81 super(PUBLIC | STATIC, name, type, owner); 1.82 this.opcode = opcode; 1.83 } 1.84 + 1.85 + public <R, P> R accept(Symbol.Visitor<R, P> v, P p) { 1.86 + return v.visitOperatorSymbol(this, p); 1.87 + } 1.88 } 1.89 1.90 /** Symbol completer interface. 1.91 @@ -1308,4 +1340,28 @@ 1.92 } 1.93 1.94 } 1.95 + 1.96 + /** 1.97 + * A visitor for symbols. A visitor is used to implement operations 1.98 + * (or relations) on symbols. Most common operations on types are 1.99 + * binary relations and this interface is designed for binary 1.100 + * relations, that is, operations on the form 1.101 + * Symbol × P → R. 1.102 + * <!-- In plain text: Type x P -> R --> 1.103 + * 1.104 + * @param <R> the return type of the operation implemented by this 1.105 + * visitor; use Void if no return type is needed. 1.106 + * @param <P> the type of the second argument (the first being the 1.107 + * symbol itself) of the operation implemented by this visitor; use 1.108 + * Void if a second argument is not needed. 1.109 + */ 1.110 + public interface Visitor<R,P> { 1.111 + R visitClassSymbol(ClassSymbol s, P arg); 1.112 + R visitMethodSymbol(MethodSymbol s, P arg); 1.113 + R visitPackageSymbol(PackageSymbol s, P arg); 1.114 + R visitOperatorSymbol(OperatorSymbol s, P arg); 1.115 + R visitVarSymbol(VarSymbol s, P arg); 1.116 + R visitTypeSymbol(TypeSymbol s, P arg); 1.117 + R visitSymbol(Symbol s, P arg); 1.118 + } 1.119 }
2.1 --- a/src/share/classes/com/sun/tools/javac/code/Types.java Mon Sep 29 11:34:43 2008 +0100 2.2 +++ b/src/share/classes/com/sun/tools/javac/code/Types.java Mon Sep 29 11:48:09 2008 +0100 2.3 @@ -67,6 +67,7 @@ 2.4 new Context.Key<Types>(); 2.5 2.6 final Symtab syms; 2.7 + final Messages messages; 2.8 final Names names; 2.9 final boolean allowBoxing; 2.10 final ClassReader reader; 2.11 @@ -92,6 +93,7 @@ 2.12 source = Source.instance(context); 2.13 chk = Check.instance(context); 2.14 capturedName = names.fromString("<captured wildcard>"); 2.15 + messages = Messages.instance(context); 2.16 } 2.17 // </editor-fold> 2.18 2.19 @@ -1589,10 +1591,10 @@ 2.20 syms.noSymbol); 2.21 if (bounds.head.tag == TYPEVAR) 2.22 // error condition, recover 2.23 - bc.erasure_field = syms.objectType; 2.24 - else 2.25 - bc.erasure_field = erasure(bounds.head); 2.26 - bc.members_field = new Scope(bc); 2.27 + bc.erasure_field = syms.objectType; 2.28 + else 2.29 + bc.erasure_field = erasure(bounds.head); 2.30 + bc.members_field = new Scope(bc); 2.31 ClassType bt = (ClassType)bc.type; 2.32 bt.allparams_field = List.nil(); 2.33 if (supertype != null) { 2.34 @@ -2249,10 +2251,234 @@ 2.35 } 2.36 // </editor-fold> 2.37 2.38 + // <editor-fold defaultstate="collapsed" desc="printType"> 2.39 + /** 2.40 + * Visitor for generating a string representation of a given type 2.41 + * accordingly to a given locale 2.42 + */ 2.43 + public String toString(Type t, Locale locale) { 2.44 + return typePrinter.visit(t, locale); 2.45 + } 2.46 + // where 2.47 + private TypePrinter typePrinter = new TypePrinter(); 2.48 + 2.49 + public class TypePrinter extends DefaultTypeVisitor<String, Locale> { 2.50 + 2.51 + public String visit(List<Type> ts, Locale locale) { 2.52 + ListBuffer<String> sbuf = lb(); 2.53 + for (Type t : ts) { 2.54 + sbuf.append(visit(t, locale)); 2.55 + } 2.56 + return sbuf.toList().toString(); 2.57 + } 2.58 + 2.59 + @Override 2.60 + public String visitCapturedType(CapturedType t, Locale locale) { 2.61 + return messages.getLocalizedString("compiler.misc.type.captureof", 2.62 + (t.hashCode() & 0xFFFFFFFFL) % Type.CapturedType.PRIME, 2.63 + visit(t.wildcard, locale)); 2.64 + } 2.65 + 2.66 + @Override 2.67 + public String visitForAll(ForAll t, Locale locale) { 2.68 + return "<" + visit(t.tvars, locale) + ">" + visit(t.qtype, locale); 2.69 + } 2.70 + 2.71 + @Override 2.72 + public String visitUndetVar(UndetVar t, Locale locale) { 2.73 + if (t.inst != null) { 2.74 + return visit(t.inst, locale); 2.75 + } else { 2.76 + return visit(t.qtype, locale) + "?"; 2.77 + } 2.78 + } 2.79 + 2.80 + @Override 2.81 + public String visitArrayType(ArrayType t, Locale locale) { 2.82 + return visit(t.elemtype, locale) + "[]"; 2.83 + } 2.84 + 2.85 + @Override 2.86 + public String visitClassType(ClassType t, Locale locale) { 2.87 + StringBuffer buf = new StringBuffer(); 2.88 + if (t.getEnclosingType().tag == CLASS && t.tsym.owner.kind == Kinds.TYP) { 2.89 + buf.append(visit(t.getEnclosingType(), locale)); 2.90 + buf.append("."); 2.91 + buf.append(className(t, false, locale)); 2.92 + } else { 2.93 + buf.append(className(t, true, locale)); 2.94 + } 2.95 + if (t.getTypeArguments().nonEmpty()) { 2.96 + buf.append('<'); 2.97 + buf.append(visit(t.getTypeArguments(), locale)); 2.98 + buf.append(">"); 2.99 + } 2.100 + return buf.toString(); 2.101 + } 2.102 + 2.103 + @Override 2.104 + public String visitMethodType(MethodType t, Locale locale) { 2.105 + return "(" + printMethodArgs(t.argtypes, false, locale) + ")" + visit(t.restype, locale); 2.106 + } 2.107 + 2.108 + @Override 2.109 + public String visitPackageType(PackageType t, Locale locale) { 2.110 + return t.tsym.getQualifiedName().toString(); 2.111 + } 2.112 + 2.113 + @Override 2.114 + public String visitWildcardType(WildcardType t, Locale locale) { 2.115 + StringBuffer s = new StringBuffer(); 2.116 + s.append(t.kind); 2.117 + if (t.kind != UNBOUND) { 2.118 + s.append(visit(t.type, locale)); 2.119 + } 2.120 + return s.toString(); 2.121 + } 2.122 + 2.123 + 2.124 + public String visitType(Type t, Locale locale) { 2.125 + String s = (t.tsym == null || t.tsym.name == null) 2.126 + ? messages.getLocalizedString("compiler.misc.type.none") 2.127 + : t.tsym.name.toString(); 2.128 + return s; 2.129 + } 2.130 + 2.131 + protected String className(ClassType t, boolean longform, Locale locale) { 2.132 + Symbol sym = t.tsym; 2.133 + if (sym.name.length() == 0 && (sym.flags() & COMPOUND) != 0) { 2.134 + StringBuffer s = new StringBuffer(visit(supertype(t), locale)); 2.135 + for (List<Type> is = interfaces(t); is.nonEmpty(); is = is.tail) { 2.136 + s.append("&"); 2.137 + s.append(visit(is.head, locale)); 2.138 + } 2.139 + return s.toString(); 2.140 + } else if (sym.name.length() == 0) { 2.141 + String s; 2.142 + ClassType norm = (ClassType) t.tsym.type; 2.143 + if (norm == null) { 2.144 + s = getLocalizedString(locale, "compiler.misc.anonymous.class", (Object) null); 2.145 + } else if (interfaces(norm).nonEmpty()) { 2.146 + s = getLocalizedString(locale, "compiler.misc.anonymous.class", 2.147 + visit(interfaces(norm).head, locale)); 2.148 + } else { 2.149 + s = getLocalizedString(locale, "compiler.misc.anonymous.class", 2.150 + visit(supertype(norm), locale)); 2.151 + } 2.152 + return s; 2.153 + } else if (longform) { 2.154 + return sym.getQualifiedName().toString(); 2.155 + } else { 2.156 + return sym.name.toString(); 2.157 + } 2.158 + } 2.159 + 2.160 + protected String printMethodArgs(List<Type> args, boolean varArgs, Locale locale) { 2.161 + if (!varArgs) { 2.162 + return visit(args, locale); 2.163 + } else { 2.164 + StringBuffer buf = new StringBuffer(); 2.165 + while (args.tail.nonEmpty()) { 2.166 + buf.append(visit(args.head, locale)); 2.167 + args = args.tail; 2.168 + buf.append(','); 2.169 + } 2.170 + if (args.head.tag == ARRAY) { 2.171 + buf.append(visit(((ArrayType) args.head).elemtype, locale)); 2.172 + buf.append("..."); 2.173 + } else { 2.174 + buf.append(visit(args.head, locale)); 2.175 + } 2.176 + return buf.toString(); 2.177 + } 2.178 + } 2.179 + 2.180 + protected String getLocalizedString(Locale locale, String key, Object... args) { 2.181 + return messages.getLocalizedString(key, args); 2.182 + } 2.183 + }; 2.184 + // </editor-fold> 2.185 + 2.186 + // <editor-fold defaultstate="collapsed" desc="printSymbol"> 2.187 + /** 2.188 + * Visitor for generating a string representation of a given symbol 2.189 + * accordingly to a given locale 2.190 + */ 2.191 + public String toString(Symbol t, Locale locale) { 2.192 + return symbolPrinter.visit(t, locale); 2.193 + } 2.194 + // where 2.195 + private SymbolPrinter symbolPrinter = new SymbolPrinter(); 2.196 + 2.197 + public class SymbolPrinter extends DefaultSymbolVisitor<String, Locale> { 2.198 + 2.199 + @Override 2.200 + public String visitClassSymbol(ClassSymbol sym, Locale locale) { 2.201 + return sym.name.isEmpty() 2.202 + ? getLocalizedString(locale, "compiler.misc.anonymous.class", sym.flatname) 2.203 + : sym.fullname.toString(); 2.204 + } 2.205 + 2.206 + @Override 2.207 + public String visitMethodSymbol(MethodSymbol s, Locale locale) { 2.208 + if ((s.flags() & BLOCK) != 0) { 2.209 + return s.owner.name.toString(); 2.210 + } else { 2.211 + String ms = (s.name == names.init) 2.212 + ? s.owner.name.toString() 2.213 + : s.name.toString(); 2.214 + if (s.type != null) { 2.215 + if (s.type.tag == FORALL) { 2.216 + ms = "<" + typePrinter.visit(s.type.getTypeArguments(), locale) + ">" + ms; 2.217 + } 2.218 + ms += "(" + typePrinter.printMethodArgs( 2.219 + s.type.getParameterTypes(), 2.220 + (s.flags() & VARARGS) != 0, 2.221 + locale) + ")"; 2.222 + } 2.223 + return ms; 2.224 + } 2.225 + } 2.226 + 2.227 + @Override 2.228 + public String visitOperatorSymbol(OperatorSymbol s, Locale locale) { 2.229 + return visitMethodSymbol(s, locale); 2.230 + } 2.231 + 2.232 + @Override 2.233 + public String visitPackageSymbol(PackageSymbol s, Locale locale) { 2.234 + return s.name.isEmpty() 2.235 + ? getLocalizedString(locale, "compiler.misc.unnamed.package") 2.236 + : s.fullname.toString(); 2.237 + } 2.238 + 2.239 + @Override 2.240 + public String visitSymbol(Symbol s, Locale locale) { 2.241 + return s.name.toString(); 2.242 + } 2.243 + 2.244 + public String visit(List<Symbol> ts, Locale locale) { 2.245 + ListBuffer<String> sbuf = lb(); 2.246 + for (Symbol t : ts) { 2.247 + sbuf.append(visit(t, locale)); 2.248 + } 2.249 + return sbuf.toList().toString(); 2.250 + } 2.251 + 2.252 + protected String getLocalizedString(Locale locale, String key, Object... args) { 2.253 + return messages.getLocalizedString(key, args); 2.254 + } 2.255 + }; 2.256 + // </editor-fold> 2.257 + 2.258 // <editor-fold defaultstate="collapsed" desc="toString"> 2.259 /** 2.260 * This toString is slightly more descriptive than the one on Type. 2.261 + * 2.262 + * @deprecated Types.toString(Type t, Locale l) provides better support 2.263 + * for localization 2.264 */ 2.265 + @Deprecated 2.266 public String toString(Type t) { 2.267 if (t.tag == FORALL) { 2.268 ForAll forAll = (ForAll)t; 2.269 @@ -3236,6 +3462,28 @@ 2.270 } 2.271 2.272 /** 2.273 + * A default visitor for symbols. All visitor methods except 2.274 + * visitSymbol are implemented by delegating to visitSymbol. Concrete 2.275 + * subclasses must provide an implementation of visitSymbol and can 2.276 + * override other methods as needed. 2.277 + * 2.278 + * @param <R> the return type of the operation implemented by this 2.279 + * visitor; use Void if no return type is needed. 2.280 + * @param <S> the type of the second argument (the first being the 2.281 + * symbol itself) of the operation implemented by this visitor; use 2.282 + * Void if a second argument is not needed. 2.283 + */ 2.284 + public static abstract class DefaultSymbolVisitor<R,S> implements Symbol.Visitor<R,S> { 2.285 + final public R visit(Symbol s, S arg) { return s.accept(this, arg); } 2.286 + public R visitClassSymbol(ClassSymbol s, S arg) { return visitSymbol(s, arg); } 2.287 + public R visitMethodSymbol(MethodSymbol s, S arg) { return visitSymbol(s, arg); } 2.288 + public R visitOperatorSymbol(OperatorSymbol s, S arg) { return visitSymbol(s, arg); } 2.289 + public R visitPackageSymbol(PackageSymbol s, S arg) { return visitSymbol(s, arg); } 2.290 + public R visitTypeSymbol(TypeSymbol s, S arg) { return visitSymbol(s, arg); } 2.291 + public R visitVarSymbol(VarSymbol s, S arg) { return visitSymbol(s, arg); } 2.292 + } 2.293 + 2.294 + /** 2.295 * A <em>simple</em> visitor for types. This visitor is simple as 2.296 * captured wildcards, for-all types (generic methods), and 2.297 * undetermined type variables (part of inference) are hidden.
3.1 --- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Sep 29 11:34:43 2008 +0100 3.2 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Sep 29 11:48:09 2008 +0100 3.3 @@ -823,6 +823,12 @@ 3.4 compiler.misc.anonymous.class=\ 3.5 <anonymous {0}> 3.6 3.7 +compiler.misc.type.captureof=\ 3.8 + capture#{0} of {1} 3.9 + 3.10 +compiler.misc.type.none=\ 3.11 + <none> 3.12 + 3.13 compiler.misc.unnamed.package=\ 3.14 unnamed package 3.15