JavacTypes.java revision 2877:62e285806e83
172445Sassar/* 2178825Sdfr * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. 372445Sassar * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 472445Sassar * 5127808Snectar * This code is free software; you can redistribute it and/or modify it 6102644Snectar * under the terms of the GNU General Public License version 2 only, as 772445Sassar * published by the Free Software Foundation. Oracle designates this 872445Sassar * particular file as subject to the "Classpath" exception as provided 972445Sassar * by Oracle in the LICENSE file that accompanied this code. 1072445Sassar * 1172445Sassar * This code is distributed in the hope that it will be useful, but WITHOUT 12102644Snectar * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1372445Sassar * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1472445Sassar * version 2 for more details (a copy is included in the LICENSE file that 1572445Sassar * accompanied this code). 16102644Snectar * 1772445Sassar * You should have received a copy of the GNU General Public License version 1872445Sassar * 2 along with this work; if not, write to the Free Software Foundation, 1972445Sassar * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2072445Sassar * 21102644Snectar * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22178825Sdfr * or visit www.oracle.com if you need additional information or have any 23102644Snectar * questions. 24102644Snectar */ 2572445Sassar 26102644Snectarpackage com.sun.tools.javac.model; 27102644Snectar 28102644Snectarimport java.util.Collection; 29102644Snectarimport java.util.Collections; 30102644Snectarimport java.util.EnumSet; 31102644Snectarimport java.util.LinkedHashSet; 32102644Snectarimport java.util.List; 33102644Snectarimport java.util.Set; 34102644Snectarimport java.util.stream.Collectors; 35102644Snectar 36102644Snectarimport javax.lang.model.element.*; 3772445Sassarimport javax.lang.model.type.*; 38102644Snectar 3972445Sassarimport com.sun.tools.javac.code.*; 4072445Sassarimport com.sun.tools.javac.code.Symbol.*; 4172445Sassarimport com.sun.tools.javac.util.*; 4272445Sassarimport com.sun.tools.javac.util.DefinedBy.Api; 4372445Sassar 4472445Sassarimport static com.sun.tools.javac.code.Kinds.Kind.*; 45102644Snectar 4672445Sassar/** 4772445Sassar * Utility methods for operating on types. 48102644Snectar * 49102644Snectar * <p><b>This is NOT part of any supported API. 50102644Snectar * If you write code that depends on this, you do so at your own 51102644Snectar * risk. This code and its internal interfaces are subject to change 52102644Snectar * or deletion without notice.</b></p> 53102644Snectar */ 54102644Snectarpublic class JavacTypes implements javax.lang.model.util.Types { 55102644Snectar 56102644Snectar private final Symtab syms; 57102644Snectar private final Types types; 58 59 public static JavacTypes instance(Context context) { 60 JavacTypes instance = context.get(JavacTypes.class); 61 if (instance == null) 62 instance = new JavacTypes(context); 63 return instance; 64 } 65 66 protected JavacTypes(Context context) { 67 context.put(JavacTypes.class, this); 68 syms = Symtab.instance(context); 69 types = Types.instance(context); 70 } 71 72 @DefinedBy(Api.LANGUAGE_MODEL) 73 public Element asElement(TypeMirror t) { 74 switch (t.getKind()) { 75 case DECLARED: 76 case INTERSECTION: 77 case ERROR: 78 case TYPEVAR: 79 Type type = cast(Type.class, t); 80 return type.asElement(); 81 default: 82 return null; 83 } 84 } 85 86 @DefinedBy(Api.LANGUAGE_MODEL) 87 public boolean isSameType(TypeMirror t1, TypeMirror t2) { 88 return types.isSameType((Type) t1, (Type) t2); 89 } 90 91 @DefinedBy(Api.LANGUAGE_MODEL) 92 public boolean isSubtype(TypeMirror t1, TypeMirror t2) { 93 validateTypeNotIn(t1, EXEC_OR_PKG); 94 validateTypeNotIn(t2, EXEC_OR_PKG); 95 return types.isSubtype((Type) t1, (Type) t2); 96 } 97 98 @DefinedBy(Api.LANGUAGE_MODEL) 99 public boolean isAssignable(TypeMirror t1, TypeMirror t2) { 100 validateTypeNotIn(t1, EXEC_OR_PKG); 101 validateTypeNotIn(t2, EXEC_OR_PKG); 102 return types.isAssignable((Type) t1, (Type) t2); 103 } 104 105 @DefinedBy(Api.LANGUAGE_MODEL) 106 public boolean contains(TypeMirror t1, TypeMirror t2) { 107 validateTypeNotIn(t1, EXEC_OR_PKG); 108 validateTypeNotIn(t2, EXEC_OR_PKG); 109 return types.containsType((Type) t1, (Type) t2); 110 } 111 112 @DefinedBy(Api.LANGUAGE_MODEL) 113 public boolean isSubsignature(ExecutableType m1, ExecutableType m2) { 114 return types.isSubSignature((Type) m1, (Type) m2); 115 } 116 117 @DefinedBy(Api.LANGUAGE_MODEL) 118 public List<Type> directSupertypes(TypeMirror t) { 119 validateTypeNotIn(t, EXEC_OR_PKG); 120 Type ty = (Type)t; 121 return types.directSupertypes(ty).stream() 122 .map(Type::stripMetadataIfNeeded) 123 .collect(Collectors.toList()); 124 } 125 126 @DefinedBy(Api.LANGUAGE_MODEL) 127 public TypeMirror erasure(TypeMirror t) { 128 if (t.getKind() == TypeKind.PACKAGE) 129 throw new IllegalArgumentException(t.toString()); 130 return types.erasure((Type)t).stripMetadataIfNeeded(); 131 } 132 133 @DefinedBy(Api.LANGUAGE_MODEL) 134 public TypeElement boxedClass(PrimitiveType p) { 135 return types.boxedClass((Type) p); 136 } 137 138 @DefinedBy(Api.LANGUAGE_MODEL) 139 public PrimitiveType unboxedType(TypeMirror t) { 140 if (t.getKind() != TypeKind.DECLARED) 141 throw new IllegalArgumentException(t.toString()); 142 Type unboxed = types.unboxedType((Type) t); 143 if (! unboxed.isPrimitive()) // only true primitives, not void 144 throw new IllegalArgumentException(t.toString()); 145 return (PrimitiveType)unboxed; 146 } 147 148 @DefinedBy(Api.LANGUAGE_MODEL) 149 public TypeMirror capture(TypeMirror t) { 150 validateTypeNotIn(t, EXEC_OR_PKG); 151 return types.capture((Type)t).stripMetadataIfNeeded(); 152 } 153 154 @DefinedBy(Api.LANGUAGE_MODEL) 155 public PrimitiveType getPrimitiveType(TypeKind kind) { 156 switch (kind) { 157 case BOOLEAN: return syms.booleanType; 158 case BYTE: return syms.byteType; 159 case SHORT: return syms.shortType; 160 case INT: return syms.intType; 161 case LONG: return syms.longType; 162 case CHAR: return syms.charType; 163 case FLOAT: return syms.floatType; 164 case DOUBLE: return syms.doubleType; 165 default: 166 throw new IllegalArgumentException("Not a primitive type: " + kind); 167 } 168 } 169 170 @DefinedBy(Api.LANGUAGE_MODEL) 171 public NullType getNullType() { 172 return (NullType) syms.botType; 173 } 174 175 @DefinedBy(Api.LANGUAGE_MODEL) 176 public NoType getNoType(TypeKind kind) { 177 switch (kind) { 178 case VOID: return syms.voidType; 179 case NONE: return Type.noType; 180 default: 181 throw new IllegalArgumentException(kind.toString()); 182 } 183 } 184 185 @DefinedBy(Api.LANGUAGE_MODEL) 186 public ArrayType getArrayType(TypeMirror componentType) { 187 switch (componentType.getKind()) { 188 case VOID: 189 case EXECUTABLE: 190 case WILDCARD: // heh! 191 case PACKAGE: 192 throw new IllegalArgumentException(componentType.toString()); 193 } 194 return new Type.ArrayType((Type) componentType, syms.arrayClass); 195 } 196 197 @DefinedBy(Api.LANGUAGE_MODEL) 198 public WildcardType getWildcardType(TypeMirror extendsBound, 199 TypeMirror superBound) { 200 BoundKind bkind; 201 Type bound; 202 if (extendsBound == null && superBound == null) { 203 bkind = BoundKind.UNBOUND; 204 bound = syms.objectType; 205 } else if (superBound == null) { 206 bkind = BoundKind.EXTENDS; 207 bound = (Type) extendsBound; 208 } else if (extendsBound == null) { 209 bkind = BoundKind.SUPER; 210 bound = (Type) superBound; 211 } else { 212 throw new IllegalArgumentException( 213 "Extends and super bounds cannot both be provided"); 214 } 215 switch (bound.getKind()) { 216 case ARRAY: 217 case DECLARED: 218 case ERROR: 219 case TYPEVAR: 220 return new Type.WildcardType(bound, bkind, syms.boundClass); 221 default: 222 throw new IllegalArgumentException(bound.toString()); 223 } 224 } 225 226 @DefinedBy(Api.LANGUAGE_MODEL) 227 public DeclaredType getDeclaredType(TypeElement typeElem, 228 TypeMirror... typeArgs) { 229 ClassSymbol sym = (ClassSymbol) typeElem; 230 231 if (typeArgs.length == 0) 232 return (DeclaredType) sym.erasure(types); 233 if (sym.type.getEnclosingType().isParameterized()) 234 throw new IllegalArgumentException(sym.toString()); 235 236 return getDeclaredType0(sym.type.getEnclosingType(), sym, typeArgs); 237 } 238 239 @DefinedBy(Api.LANGUAGE_MODEL) 240 public DeclaredType getDeclaredType(DeclaredType enclosing, 241 TypeElement typeElem, 242 TypeMirror... typeArgs) { 243 if (enclosing == null) 244 return getDeclaredType(typeElem, typeArgs); 245 246 ClassSymbol sym = (ClassSymbol) typeElem; 247 Type outer = (Type) enclosing; 248 249 if (outer.tsym != sym.owner.enclClass()) 250 throw new IllegalArgumentException(enclosing.toString()); 251 if (!outer.isParameterized()) 252 return getDeclaredType(typeElem, typeArgs); 253 254 return getDeclaredType0(outer, sym, typeArgs); 255 } 256 // where 257 private DeclaredType getDeclaredType0(Type outer, 258 ClassSymbol sym, 259 TypeMirror... typeArgs) { 260 if (typeArgs.length != sym.type.getTypeArguments().length()) 261 throw new IllegalArgumentException( 262 "Incorrect number of type arguments"); 263 264 ListBuffer<Type> targs = new ListBuffer<>(); 265 for (TypeMirror t : typeArgs) { 266 if (!(t instanceof ReferenceType || t instanceof WildcardType)) 267 throw new IllegalArgumentException(t.toString()); 268 targs.append((Type) t); 269 } 270 // TODO: Would like a way to check that type args match formals. 271 272 return (DeclaredType) new Type.ClassType(outer, targs.toList(), sym); 273 } 274 275 /** 276 * Returns the type of an element when that element is viewed as 277 * a member of, or otherwise directly contained by, a given type. 278 * For example, 279 * when viewed as a member of the parameterized type {@code Set<String>}, 280 * the {@code Set.add} method is an {@code ExecutableType} 281 * whose parameter is of type {@code String}. 282 * 283 * @param containing the containing type 284 * @param element the element 285 * @return the type of the element as viewed from the containing type 286 * @throws IllegalArgumentException if the element is not a valid one 287 * for the given type 288 */ 289 @DefinedBy(Api.LANGUAGE_MODEL) 290 public TypeMirror asMemberOf(DeclaredType containing, Element element) { 291 Type site = (Type)containing; 292 Symbol sym = (Symbol)element; 293 if (types.asSuper(site, sym.getEnclosingElement()) == null) 294 throw new IllegalArgumentException(sym + "@" + site); 295 return types.memberType(site, sym); 296 } 297 298 299 private static final Set<TypeKind> EXEC_OR_PKG = 300 EnumSet.of(TypeKind.EXECUTABLE, TypeKind.PACKAGE); 301 302 /** 303 * Throws an IllegalArgumentException if a type's kind is one of a set. 304 */ 305 private void validateTypeNotIn(TypeMirror t, Set<TypeKind> invalidKinds) { 306 if (invalidKinds.contains(t.getKind())) 307 throw new IllegalArgumentException(t.toString()); 308 } 309 310 /** 311 * Returns an object cast to the specified type. 312 * @throws NullPointerException if the object is {@code null} 313 * @throws IllegalArgumentException if the object is of the wrong type 314 */ 315 private static <T> T cast(Class<T> clazz, Object o) { 316 if (! clazz.isInstance(o)) 317 throw new IllegalArgumentException(o.toString()); 318 return clazz.cast(o); 319 } 320 321 public Set<MethodSymbol> getOverriddenMethods(Element elem) { 322 if (elem.getKind() != ElementKind.METHOD 323 || elem.getModifiers().contains(Modifier.STATIC) 324 || elem.getModifiers().contains(Modifier.PRIVATE)) 325 return Collections.emptySet(); 326 327 if (!(elem instanceof MethodSymbol)) 328 throw new IllegalArgumentException(); 329 330 MethodSymbol m = (MethodSymbol) elem; 331 ClassSymbol origin = (ClassSymbol) m.owner; 332 333 Set<MethodSymbol> results = new LinkedHashSet<>(); 334 for (Type t : types.closure(origin.type)) { 335 if (t != origin.type) { 336 ClassSymbol c = (ClassSymbol) t.tsym; 337 for (Symbol sym : c.members().getSymbolsByName(m.name)) { 338 if (sym.kind == MTH && m.overrides(sym, origin, types, true)) { 339 results.add((MethodSymbol) sym); 340 } 341 } 342 } 343 } 344 345 return results; 346 } 347} 348