Sun, 17 Feb 2013 16:44:55 -0500
Merge
1 /*
2 * Copyright (c) 2009, 2013, 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 */
26 package com.sun.tools.javac.code;
28 import java.util.Locale;
30 import javax.lang.model.type.TypeKind;
32 import com.sun.tools.javac.api.Messages;
33 import com.sun.tools.javac.code.Type.AnnotatedType;
34 import com.sun.tools.javac.code.Symbol.*;
35 import com.sun.tools.javac.code.Type.*;
36 import com.sun.tools.javac.util.List;
37 import com.sun.tools.javac.util.ListBuffer;
39 import static com.sun.tools.javac.code.BoundKind.*;
40 import static com.sun.tools.javac.code.Flags.*;
41 import static com.sun.tools.javac.code.TypeTag.CLASS;
42 import static com.sun.tools.javac.code.TypeTag.FORALL;
44 /**
45 * A combined type/symbol visitor for generating non-trivial localized string
46 * representation of types and symbols.
47 *
48 * <p><b>This is NOT part of any supported API.
49 * If you write code that depends on this, you do so at your own risk.
50 * This code and its internal interfaces are subject to change or
51 * deletion without notice.</b>
52 */
53 public abstract class Printer implements Type.Visitor<String, Locale>, Symbol.Visitor<String, Locale> {
55 List<Type> seenCaptured = List.nil();
56 static final int PRIME = 997; // largest prime less than 1000
58 protected Printer() { }
60 /**
61 * This method should be overriden in order to provide proper i18n support.
62 *
63 * @param locale the locale in which the string is to be rendered
64 * @param key the key corresponding to the message to be displayed
65 * @param args a list of optional arguments
66 * @return localized string representation
67 */
68 protected abstract String localize(Locale locale, String key, Object... args);
70 /**
71 * Maps a captured type into an unique identifier.
72 *
73 * @param t the captured type for which an id is to be retrieved
74 * @param locale locale settings
75 * @return unique id representing this captured type
76 */
77 protected abstract String capturedVarId(CapturedType t, Locale locale);
79 /**
80 * Create a printer with default i18n support provided by Messages. By default,
81 * captured types ids are generated using hashcode.
82 *
83 * @param messages Messages class to be used for i18n
84 * @return printer visitor instance
85 */
86 public static Printer createStandardPrinter(final Messages messages) {
87 return new Printer() {
88 @Override
89 protected String localize(Locale locale, String key, Object... args) {
90 return messages.getLocalizedString(locale, key, args);
91 }
93 @Override
94 protected String capturedVarId(CapturedType t, Locale locale) {
95 return (t.hashCode() & 0xFFFFFFFFL) % PRIME + "";
96 }};
97 }
99 /**
100 * Get a localized string representation for all the types in the input list.
101 *
102 * @param ts types to be displayed
103 * @param locale the locale in which the string is to be rendered
104 * @return localized string representation
105 */
106 public String visitTypes(List<Type> ts, Locale locale) {
107 ListBuffer<String> sbuf = ListBuffer.lb();
108 for (Type t : ts) {
109 sbuf.append(visit(t, locale));
110 }
111 return sbuf.toList().toString();
112 }
114 /**
115 * * Get a localized string representation for all the symbols in the input list.
116 *
117 * @param ts symbols to be displayed
118 * @param locale the locale in which the string is to be rendered
119 * @return localized string representation
120 */
121 public String visitSymbols(List<Symbol> ts, Locale locale) {
122 ListBuffer<String> sbuf = ListBuffer.lb();
123 for (Symbol t : ts) {
124 sbuf.append(visit(t, locale));
125 }
126 return sbuf.toList().toString();
127 }
129 /**
130 * Get a localized string represenation for a given type.
131 *
132 * @param t type to be displayed
133 * @param locale the locale in which the string is to be rendered
134 * @return localized string representation
135 */
136 public String visit(Type t, Locale locale) {
137 return t.accept(this, locale);
138 }
140 /**
141 * Get a localized string represenation for a given symbol.
142 *
143 * @param s symbol to be displayed
144 * @param locale the locale in which the string is to be rendered
145 * @return localized string representation
146 */
147 public String visit(Symbol s, Locale locale) {
148 return s.accept(this, locale);
149 }
151 @Override
152 public String visitCapturedType(CapturedType t, Locale locale) {
153 if (seenCaptured.contains(t))
154 return localize(locale, "compiler.misc.type.captureof.1",
155 capturedVarId(t, locale));
156 else {
157 try {
158 seenCaptured = seenCaptured.prepend(t);
159 return localize(locale, "compiler.misc.type.captureof",
160 capturedVarId(t, locale),
161 visit(t.wildcard, locale));
162 }
163 finally {
164 seenCaptured = seenCaptured.tail;
165 }
166 }
167 }
169 @Override
170 public String visitForAll(ForAll t, Locale locale) {
171 return "<" + visitTypes(t.tvars, locale) + ">" + visit(t.qtype, locale);
172 }
174 @Override
175 public String visitUndetVar(UndetVar t, Locale locale) {
176 if (t.inst != null) {
177 return visit(t.inst, locale);
178 } else {
179 return visit(t.qtype, locale) + "?";
180 }
181 }
183 @Override
184 public String visitArrayType(ArrayType t, Locale locale) {
185 return visit(t.elemtype, locale) + "[]";
186 }
188 @Override
189 public String visitClassType(ClassType t, Locale locale) {
190 StringBuilder buf = new StringBuilder();
191 if (t.getEnclosingType().tag == CLASS && t.tsym.owner.kind == Kinds.TYP) {
192 buf.append(visit(t.getEnclosingType(), locale));
193 buf.append('.');
194 buf.append(className(t, false, locale));
195 } else {
196 buf.append(className(t, true, locale));
197 }
198 if (t.getTypeArguments().nonEmpty()) {
199 buf.append('<');
200 buf.append(visitTypes(t.getTypeArguments(), locale));
201 buf.append('>');
202 }
203 return buf.toString();
204 }
206 @Override
207 public String visitMethodType(MethodType t, Locale locale) {
208 return "(" + printMethodArgs(t.argtypes, false, locale) + ")" + visit(t.restype, locale);
209 }
211 @Override
212 public String visitPackageType(PackageType t, Locale locale) {
213 return t.tsym.getQualifiedName().toString();
214 }
216 @Override
217 public String visitWildcardType(WildcardType t, Locale locale) {
218 StringBuilder s = new StringBuilder();
219 s.append(t.kind);
220 if (t.kind != UNBOUND) {
221 s.append(visit(t.type, locale));
222 }
223 return s.toString();
224 }
226 @Override
227 public String visitErrorType(ErrorType t, Locale locale) {
228 return visitType(t, locale);
229 }
231 @Override
232 public String visitTypeVar(TypeVar t, Locale locale) {
233 return visitType(t, locale);
234 }
236 @Override
237 public String visitAnnotatedType(AnnotatedType t, Locale locale) {
238 if (t.typeAnnotations != null &&
239 t.typeAnnotations.nonEmpty()) {
240 // TODO: better logic for arrays, ...
241 return "(" + t.typeAnnotations + " :: " + visit(t.underlyingType, locale) + ")";
242 } else {
243 return "({} :: " + visit(t.underlyingType, locale) + ")";
244 }
245 }
247 public String visitType(Type t, Locale locale) {
248 String s = (t.tsym == null || t.tsym.name == null)
249 ? localize(locale, "compiler.misc.type.none")
250 : t.tsym.name.toString();
251 return s;
252 }
254 /**
255 * Converts a class name into a (possibly localized) string. Anonymous
256 * inner classes gets converted into a localized string.
257 *
258 * @param t the type of the class whose name is to be rendered
259 * @param longform if set, the class' fullname is displayed - if unset the
260 * short name is chosen (w/o package)
261 * @param locale the locale in which the string is to be rendered
262 * @return localized string representation
263 */
264 protected String className(ClassType t, boolean longform, Locale locale) {
265 Symbol sym = t.tsym;
266 if (sym.name.length() == 0 && (sym.flags() & COMPOUND) != 0) {
267 StringBuilder s = new StringBuilder(visit(t.supertype_field, locale));
268 for (List<Type> is = t.interfaces_field; is.nonEmpty(); is = is.tail) {
269 s.append("&");
270 s.append(visit(is.head, locale));
271 }
272 return s.toString();
273 } else if (sym.name.length() == 0) {
274 String s;
275 ClassType norm = (ClassType) t.tsym.type;
276 if (norm == null) {
277 s = localize(locale, "compiler.misc.anonymous.class", (Object) null);
278 } else if (norm.interfaces_field != null && norm.interfaces_field.nonEmpty()) {
279 s = localize(locale, "compiler.misc.anonymous.class",
280 visit(norm.interfaces_field.head, locale));
281 } else {
282 s = localize(locale, "compiler.misc.anonymous.class",
283 visit(norm.supertype_field, locale));
284 }
285 return s;
286 } else if (longform) {
287 return sym.getQualifiedName().toString();
288 } else {
289 return sym.name.toString();
290 }
291 }
293 /**
294 * Converts a set of method argument types into their corresponding
295 * localized string representation.
296 *
297 * @param args arguments to be rendered
298 * @param varArgs if true, the last method argument is regarded as a vararg
299 * @param locale the locale in which the string is to be rendered
300 * @return localized string representation
301 */
302 protected String printMethodArgs(List<Type> args, boolean varArgs, Locale locale) {
303 if (!varArgs) {
304 return visitTypes(args, locale);
305 } else {
306 StringBuilder buf = new StringBuilder();
307 while (args.tail.nonEmpty()) {
308 buf.append(visit(args.head, locale));
309 args = args.tail;
310 buf.append(',');
311 }
312 if (args.head.unannotatedType().getKind() == TypeKind.ARRAY) {
313 buf.append(visit(((ArrayType) args.head.unannotatedType()).elemtype, locale));
314 if (args.head.getAnnotations().nonEmpty()) {
315 buf.append(' ');
316 buf.append(args.head.getAnnotations());
317 buf.append(' ');
318 }
319 buf.append("...");
320 } else {
321 buf.append(visit(args.head, locale));
322 }
323 return buf.toString();
324 }
325 }
327 @Override
328 public String visitClassSymbol(ClassSymbol sym, Locale locale) {
329 return sym.name.isEmpty()
330 ? localize(locale, "compiler.misc.anonymous.class", sym.flatname)
331 : sym.fullname.toString();
332 }
334 @Override
335 public String visitMethodSymbol(MethodSymbol s, Locale locale) {
336 if (s.isStaticOrInstanceInit()) {
337 return s.owner.name.toString();
338 } else {
339 String ms = (s.name == s.name.table.names.init)
340 ? s.owner.name.toString()
341 : s.name.toString();
342 if (s.type != null) {
343 if (s.type.tag == FORALL) {
344 ms = "<" + visitTypes(s.type.getTypeArguments(), locale) + ">" + ms;
345 }
346 ms += "(" + printMethodArgs(
347 s.type.getParameterTypes(),
348 (s.flags() & VARARGS) != 0,
349 locale) + ")";
350 }
351 return ms;
352 }
353 }
355 @Override
356 public String visitOperatorSymbol(OperatorSymbol s, Locale locale) {
357 return visitMethodSymbol(s, locale);
358 }
360 @Override
361 public String visitPackageSymbol(PackageSymbol s, Locale locale) {
362 return s.isUnnamed()
363 ? localize(locale, "compiler.misc.unnamed.package")
364 : s.fullname.toString();
365 }
367 @Override
368 public String visitTypeSymbol(TypeSymbol s, Locale locale) {
369 return visitSymbol(s, locale);
370 }
372 @Override
373 public String visitVarSymbol(VarSymbol s, Locale locale) {
374 return visitSymbol(s, locale);
375 }
377 @Override
378 public String visitSymbol(Symbol s, Locale locale) {
379 return s.name.toString();
380 }
381 }