langtools/src/share/classes/com/sun/tools/javac/code/Types.java
changeset 1357 e2d4f3e1f805
parent 1260 a772ba9ba43d
child 1469 9c381121f301
--- 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<Types>();
 
     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("<captured wildcard>");
+        messages = Messages.instance(context);
     }
     // </editor-fold>
 
@@ -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 @@
     }
     // </editor-fold>
 
+    // <editor-fold defaultstate="collapsed" desc="printType">
+    /**
+     * 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<String, Locale> {
+
+        public String visit(List<Type> ts, Locale locale) {
+            ListBuffer<String> 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<Type> 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<Type> 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);
+        }
+    };
+    // </editor-fold>
+
+    // <editor-fold defaultstate="collapsed" desc="printSymbol">
+    /**
+     * 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<String, Locale> {
+
+        @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<Symbol> ts, Locale locale) {
+            ListBuffer<String> 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);
+        }
+    };
+    // </editor-fold>
+
     // <editor-fold defaultstate="collapsed" desc="toString">
     /**
      * 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 <R> the return type of the operation implemented by this
+     * visitor; use Void if no return type is needed.
+     * @param <S> 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<R,S> implements Symbol.Visitor<R,S> {
+        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 <em>simple</em> visitor for types.  This visitor is simple as
      * captured wildcards, for-all types (generic methods), and
      * undetermined type variables (part of inference) are hidden.