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