1 /* 2 * Copyright (c) 2015, 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 */ 25 26 package jdk.jshell; 27 28 import static com.sun.tools.javac.code.Flags.COMPOUND; 29 import static com.sun.tools.javac.code.Kinds.Kind.PCK; 30 import com.sun.tools.javac.code.Printer; 31 import com.sun.tools.javac.code.Symbol; 32 import com.sun.tools.javac.code.Symbol.ClassSymbol; 33 import com.sun.tools.javac.code.Symbol.PackageSymbol; 34 import com.sun.tools.javac.code.Type; 35 import com.sun.tools.javac.code.Type.ClassType; 36 import com.sun.tools.javac.util.JavacMessages; 37 import java.util.Locale; 38 import java.util.function.BinaryOperator; 39 40 /** 41 * Print types in source form. 42 */ 43 class TypePrinter extends Printer { 44 private static final String OBJECT = "Object"; 45 46 private final JavacMessages messages; 47 private final BinaryOperator<String> fullClassNameAndPackageToClass; 48 private boolean useWildCard = false; 49 50 TypePrinter(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass, Type typeToPrint) { 51 this.messages = messages; 52 this.fullClassNameAndPackageToClass = fullClassNameAndPackageToClass; 53 } 54 55 @Override 56 protected String localize(Locale locale, String key, Object... args) { 57 return messages.getLocalizedString(locale, key, args); 58 } 59 60 @Override 61 protected String capturedVarId(Type.CapturedType t, Locale locale) { 62 throw new InternalError("should never call this"); 63 } 64 65 @Override 66 public String visitCapturedType(Type.CapturedType t, Locale locale) { 67 return visit(t.wildcard, locale); 68 } 69 70 @Override 71 public String visitWildcardType(Type.WildcardType wt, Locale locale) { 72 if (useWildCard) { // at TypeArgument(ex: List<? extends T>) 73 return super.visitWildcardType(wt, locale); 74 } else { // at TopLevelType(ex: ? extends List<T>, ? extends Number[][]) 75 Type extendsBound = wt.getExtendsBound(); 76 return extendsBound == null 77 ? OBJECT 78 : visit(extendsBound, locale); 79 } 80 } 81 82 @Override 83 public String visitType(Type t, Locale locale) { 84 String s = (t.tsym == null || t.tsym.name == null) 85 ? OBJECT // none 86 : t.tsym.name.toString(); 87 return s; 88 } 89 90 @Override 91 public String visitClassType(ClassType ct, Locale locale) { 92 boolean prevUseWildCard = useWildCard; 93 try { 94 useWildCard = true; 95 return super.visitClassType(ct, locale); 96 } finally { 97 useWildCard = prevUseWildCard; 98 } 99 } 100 101 /** 102 * Converts a class name into a (possibly localized) string. Anonymous 103 * inner classes get converted into a localized string. 104 * 105 * @param t the type of the class whose name is to be rendered 106 * @param longform if set, the class' fullname is displayed - if unset the 107 * short name is chosen (w/o package) 108 * @param locale the locale in which the string is to be rendered 109 * @return localized string representation 110 */ 111 @Override 112 protected String className(ClassType t, boolean longform, Locale locale) { 113 Symbol sym = t.tsym; 114 if (sym.name.length() == 0 && (sym.flags() & COMPOUND) != 0) { 115 /*** 116 StringBuilder s = new StringBuilder(visit(t.supertype_field, locale)); 117 for (List<Type> is = t.interfaces_field; is.nonEmpty(); is = is.tail) { 118 s.append('&'); 119 s.append(visit(is.head, locale)); 120 } 121 return s.toString(); 122 ***/ 123 return OBJECT; 124 } else if (sym.name.length() == 0) { 125 // Anonymous 126 String s; 127 ClassType norm = (ClassType) t.tsym.type; 128 if (norm == null) { 129 s = "object"; 130 } else if (norm.interfaces_field != null && norm.interfaces_field.nonEmpty()) { 131 s = visit(norm.interfaces_field.head, locale); 132 } else { 133 s = visit(norm.supertype_field, locale); 134 } 135 return s; 136 } else if (longform) { 137 String pkg = ""; 138 for (Symbol psym = sym; psym != null; psym = psym.owner) { 139 if (psym.kind == PCK) { 140 pkg = psym.getQualifiedName().toString(); 141 break; 142 } 143 } 144 return fullClassNameAndPackageToClass.apply( 145 sym.getQualifiedName().toString(), 146 pkg 147 ); 148 } else { 149 return sym.name.toString(); 150 } 151 } 152 153 @Override 154 public String visitClassSymbol(ClassSymbol sym, Locale locale) { 155 return sym.name.isEmpty() 156 ? sym.flatname.toString() // Anonymous 157 : sym.fullname.toString(); 158 } 159 160 @Override 161 public String visitPackageSymbol(PackageSymbol s, Locale locale) { 162 return s.isUnnamed() 163 ? "" // Unnamed package 164 : s.fullname.toString(); 165 } 166 167 }