JavacTypes.java revision 2601:8e638f046bf0
138494Sobrien/* 2310490Scy * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. 338494Sobrien * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 438494Sobrien * 538494Sobrien * This code is free software; you can redistribute it and/or modify it 638494Sobrien * under the terms of the GNU General Public License version 2 only, as 738494Sobrien * published by the Free Software Foundation. Oracle designates this 838494Sobrien * particular file as subject to the "Classpath" exception as provided 938494Sobrien * by Oracle in the LICENSE file that accompanied this code. 1038494Sobrien * 1138494Sobrien * This code is distributed in the hope that it will be useful, but WITHOUT 1238494Sobrien * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1338494Sobrien * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1438494Sobrien * version 2 for more details (a copy is included in the LICENSE file that 1538494Sobrien * accompanied this code). 1638494Sobrien * 1738494Sobrien * You should have received a copy of the GNU General Public License version 1838494Sobrien * 2 along with this work; if not, write to the Free Software Foundation, 19310490Scy * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2038494Sobrien * 2138494Sobrien * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2238494Sobrien * or visit www.oracle.com if you need additional information or have any 2338494Sobrien * questions. 2438494Sobrien */ 2538494Sobrien 2638494Sobrienpackage com.sun.tools.javac.model; 2738494Sobrien 2838494Sobrienimport java.util.Collections; 2938494Sobrienimport java.util.EnumSet; 3038494Sobrienimport java.util.LinkedHashSet; 3138494Sobrienimport java.util.List; 3238494Sobrienimport java.util.Set; 3338494Sobrien 3438494Sobrienimport javax.lang.model.element.*; 3538494Sobrienimport javax.lang.model.type.*; 36174294Sobrien 3738494Sobrienimport com.sun.tools.javac.code.*; 3838494Sobrienimport com.sun.tools.javac.code.Symbol.*; 3938494Sobrienimport com.sun.tools.javac.util.*; 4038494Sobrienimport com.sun.tools.javac.util.DefinedBy.Api; 4138494Sobrien 4238494Sobrien/** 4338494Sobrien * Utility methods for operating on types. 4438494Sobrien * 4538494Sobrien * <p><b>This is NOT part of any supported API. 4638494Sobrien * If you write code that depends on this, you do so at your own 4738494Sobrien * risk. This code and its internal interfaces are subject to change 4838494Sobrien * or deletion without notice.</b></p> 4938494Sobrien */ 5038494Sobrienpublic class JavacTypes implements javax.lang.model.util.Types { 5138494Sobrien 5238494Sobrien private final Symtab syms; 5338494Sobrien private final Types types; 5438494Sobrien 5538494Sobrien public static JavacTypes instance(Context context) { 5638494Sobrien JavacTypes instance = context.get(JavacTypes.class); 5738494Sobrien if (instance == null) 5838494Sobrien instance = new JavacTypes(context); 5938494Sobrien return instance; 6038494Sobrien } 6138494Sobrien 6238494Sobrien protected JavacTypes(Context context) { 6338494Sobrien context.put(JavacTypes.class, this); 6438494Sobrien syms = Symtab.instance(context); 6538494Sobrien types = Types.instance(context); 6638494Sobrien } 6738494Sobrien 6838494Sobrien @DefinedBy(Api.LANGUAGE_MODEL) 6938494Sobrien public Element asElement(TypeMirror t) { 7038494Sobrien switch (t.getKind()) { 7138494Sobrien case DECLARED: 7238494Sobrien case INTERSECTION: 7338494Sobrien case ERROR: 7438494Sobrien case TYPEVAR: 7538494Sobrien Type type = cast(Type.class, t); 7638494Sobrien return type.asElement(); 7738494Sobrien default: 7838494Sobrien return null; 7938494Sobrien } 8038494Sobrien } 8138494Sobrien 8238494Sobrien @DefinedBy(Api.LANGUAGE_MODEL) 8338494Sobrien public boolean isSameType(TypeMirror t1, TypeMirror t2) { 8438494Sobrien return types.isSameType((Type) t1, (Type) t2); 8538494Sobrien } 8638494Sobrien 8738494Sobrien @DefinedBy(Api.LANGUAGE_MODEL) 8838494Sobrien public boolean isSubtype(TypeMirror t1, TypeMirror t2) { 8938494Sobrien validateTypeNotIn(t1, EXEC_OR_PKG); 9038494Sobrien validateTypeNotIn(t2, EXEC_OR_PKG); 9138494Sobrien return types.isSubtype((Type) t1, (Type) t2); 92 } 93 94 @DefinedBy(Api.LANGUAGE_MODEL) 95 public boolean isAssignable(TypeMirror t1, TypeMirror t2) { 96 validateTypeNotIn(t1, EXEC_OR_PKG); 97 validateTypeNotIn(t2, EXEC_OR_PKG); 98 return types.isAssignable((Type) t1, (Type) t2); 99 } 100 101 @DefinedBy(Api.LANGUAGE_MODEL) 102 public boolean contains(TypeMirror t1, TypeMirror t2) { 103 validateTypeNotIn(t1, EXEC_OR_PKG); 104 validateTypeNotIn(t2, EXEC_OR_PKG); 105 return types.containsType((Type) t1, (Type) t2); 106 } 107 108 @DefinedBy(Api.LANGUAGE_MODEL) 109 public boolean isSubsignature(ExecutableType m1, ExecutableType m2) { 110 return types.isSubSignature((Type) m1, (Type) m2); 111 } 112 113 @DefinedBy(Api.LANGUAGE_MODEL) 114 public List<Type> directSupertypes(TypeMirror t) { 115 validateTypeNotIn(t, EXEC_OR_PKG); 116 return types.directSupertypes((Type) t); 117 } 118 119 @DefinedBy(Api.LANGUAGE_MODEL) 120 public TypeMirror erasure(TypeMirror t) { 121 if (t.getKind() == TypeKind.PACKAGE) 122 throw new IllegalArgumentException(t.toString()); 123 return types.erasure((Type) t); 124 } 125 126 @DefinedBy(Api.LANGUAGE_MODEL) 127 public TypeElement boxedClass(PrimitiveType p) { 128 return types.boxedClass((Type) p); 129 } 130 131 @DefinedBy(Api.LANGUAGE_MODEL) 132 public PrimitiveType unboxedType(TypeMirror t) { 133 if (t.getKind() != TypeKind.DECLARED) 134 throw new IllegalArgumentException(t.toString()); 135 Type unboxed = types.unboxedType((Type) t); 136 if (! unboxed.isPrimitive()) // only true primitives, not void 137 throw new IllegalArgumentException(t.toString()); 138 return (PrimitiveType)unboxed; 139 } 140 141 @DefinedBy(Api.LANGUAGE_MODEL) 142 public TypeMirror capture(TypeMirror t) { 143 validateTypeNotIn(t, EXEC_OR_PKG); 144 return types.capture((Type) t); 145 } 146 147 @DefinedBy(Api.LANGUAGE_MODEL) 148 public PrimitiveType getPrimitiveType(TypeKind kind) { 149 switch (kind) { 150 case BOOLEAN: return syms.booleanType; 151 case BYTE: return syms.byteType; 152 case SHORT: return syms.shortType; 153 case INT: return syms.intType; 154 case LONG: return syms.longType; 155 case CHAR: return syms.charType; 156 case FLOAT: return syms.floatType; 157 case DOUBLE: return syms.doubleType; 158 default: 159 throw new IllegalArgumentException("Not a primitive type: " + kind); 160 } 161 } 162 163 @DefinedBy(Api.LANGUAGE_MODEL) 164 public NullType getNullType() { 165 return (NullType) syms.botType; 166 } 167 168 @DefinedBy(Api.LANGUAGE_MODEL) 169 public NoType getNoType(TypeKind kind) { 170 switch (kind) { 171 case VOID: return syms.voidType; 172 case NONE: return Type.noType; 173 default: 174 throw new IllegalArgumentException(kind.toString()); 175 } 176 } 177 178 @DefinedBy(Api.LANGUAGE_MODEL) 179 public ArrayType getArrayType(TypeMirror componentType) { 180 switch (componentType.getKind()) { 181 case VOID: 182 case EXECUTABLE: 183 case WILDCARD: // heh! 184 case PACKAGE: 185 throw new IllegalArgumentException(componentType.toString()); 186 } 187 return new Type.ArrayType((Type) componentType, syms.arrayClass, 188 Type.noAnnotations); 189 } 190 191 @DefinedBy(Api.LANGUAGE_MODEL) 192 public WildcardType getWildcardType(TypeMirror extendsBound, 193 TypeMirror superBound) { 194 BoundKind bkind; 195 Type bound; 196 if (extendsBound == null && superBound == null) { 197 bkind = BoundKind.UNBOUND; 198 bound = syms.objectType; 199 } else if (superBound == null) { 200 bkind = BoundKind.EXTENDS; 201 bound = (Type) extendsBound; 202 } else if (extendsBound == null) { 203 bkind = BoundKind.SUPER; 204 bound = (Type) superBound; 205 } else { 206 throw new IllegalArgumentException( 207 "Extends and super bounds cannot both be provided"); 208 } 209 switch (bound.getKind()) { 210 case ARRAY: 211 case DECLARED: 212 case ERROR: 213 case TYPEVAR: 214 return new Type.WildcardType(bound, bkind, syms.boundClass, 215 Type.noAnnotations); 216 default: 217 throw new IllegalArgumentException(bound.toString()); 218 } 219 } 220 221 @DefinedBy(Api.LANGUAGE_MODEL) 222 public DeclaredType getDeclaredType(TypeElement typeElem, 223 TypeMirror... typeArgs) { 224 ClassSymbol sym = (ClassSymbol) typeElem; 225 226 if (typeArgs.length == 0) 227 return (DeclaredType) sym.erasure(types); 228 if (sym.type.getEnclosingType().isParameterized()) 229 throw new IllegalArgumentException(sym.toString()); 230 231 return getDeclaredType0(sym.type.getEnclosingType(), sym, typeArgs); 232 } 233 234 @DefinedBy(Api.LANGUAGE_MODEL) 235 public DeclaredType getDeclaredType(DeclaredType enclosing, 236 TypeElement typeElem, 237 TypeMirror... typeArgs) { 238 if (enclosing == null) 239 return getDeclaredType(typeElem, typeArgs); 240 241 ClassSymbol sym = (ClassSymbol) typeElem; 242 Type outer = (Type) enclosing; 243 244 if (outer.tsym != sym.owner.enclClass()) 245 throw new IllegalArgumentException(enclosing.toString()); 246 if (!outer.isParameterized()) 247 return getDeclaredType(typeElem, typeArgs); 248 249 return getDeclaredType0(outer, sym, typeArgs); 250 } 251 // where 252 private DeclaredType getDeclaredType0(Type outer, 253 ClassSymbol sym, 254 TypeMirror... typeArgs) { 255 if (typeArgs.length != sym.type.getTypeArguments().length()) 256 throw new IllegalArgumentException( 257 "Incorrect number of type arguments"); 258 259 ListBuffer<Type> targs = new ListBuffer<>(); 260 for (TypeMirror t : typeArgs) { 261 if (!(t instanceof ReferenceType || t instanceof WildcardType)) 262 throw new IllegalArgumentException(t.toString()); 263 targs.append((Type) t); 264 } 265 // TODO: Would like a way to check that type args match formals. 266 267 return (DeclaredType) new Type.ClassType(outer, targs.toList(), sym, 268 Type.noAnnotations); 269 } 270 271 /** 272 * Returns the type of an element when that element is viewed as 273 * a member of, or otherwise directly contained by, a given type. 274 * For example, 275 * when viewed as a member of the parameterized type {@code Set<String>}, 276 * the {@code Set.add} method is an {@code ExecutableType} 277 * whose parameter is of type {@code String}. 278 * 279 * @param containing the containing type 280 * @param element the element 281 * @return the type of the element as viewed from the containing type 282 * @throws IllegalArgumentException if the element is not a valid one 283 * for the given type 284 */ 285 @DefinedBy(Api.LANGUAGE_MODEL) 286 public TypeMirror asMemberOf(DeclaredType containing, Element element) { 287 Type site = (Type)containing; 288 Symbol sym = (Symbol)element; 289 if (types.asSuper(site, sym.getEnclosingElement()) == null) 290 throw new IllegalArgumentException(sym + "@" + site); 291 return types.memberType(site, sym); 292 } 293 294 295 private static final Set<TypeKind> EXEC_OR_PKG = 296 EnumSet.of(TypeKind.EXECUTABLE, TypeKind.PACKAGE); 297 298 /** 299 * Throws an IllegalArgumentException if a type's kind is one of a set. 300 */ 301 private void validateTypeNotIn(TypeMirror t, Set<TypeKind> invalidKinds) { 302 if (invalidKinds.contains(t.getKind())) 303 throw new IllegalArgumentException(t.toString()); 304 } 305 306 /** 307 * Returns an object cast to the specified type. 308 * @throws NullPointerException if the object is {@code null} 309 * @throws IllegalArgumentException if the object is of the wrong type 310 */ 311 private static <T> T cast(Class<T> clazz, Object o) { 312 if (! clazz.isInstance(o)) 313 throw new IllegalArgumentException(o.toString()); 314 return clazz.cast(o); 315 } 316 317 public Set<MethodSymbol> getOverriddenMethods(Element elem) { 318 if (elem.getKind() != ElementKind.METHOD 319 || elem.getModifiers().contains(Modifier.STATIC) 320 || elem.getModifiers().contains(Modifier.PRIVATE)) 321 return Collections.emptySet(); 322 323 if (!(elem instanceof MethodSymbol)) 324 throw new IllegalArgumentException(); 325 326 MethodSymbol m = (MethodSymbol) elem; 327 ClassSymbol origin = (ClassSymbol) m.owner; 328 329 Set<MethodSymbol> results = new LinkedHashSet<>(); 330 for (Type t : types.closure(origin.type)) { 331 if (t != origin.type) { 332 ClassSymbol c = (ClassSymbol) t.tsym; 333 for (Symbol sym : c.members().getSymbolsByName(m.name)) { 334 if (sym.kind == Kinds.MTH && m.overrides(sym, origin, types, true)) { 335 results.add((MethodSymbol) sym); 336 } 337 } 338 } 339 } 340 341 return results; 342 } 343} 344