JavacTypes.java revision 2601:8e638f046bf0
1/* 2 * Copyright (c) 2005, 2014, 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 26package com.sun.tools.javac.model; 27 28import java.util.Collections; 29import java.util.EnumSet; 30import java.util.LinkedHashSet; 31import java.util.List; 32import java.util.Set; 33 34import javax.lang.model.element.*; 35import javax.lang.model.type.*; 36 37import com.sun.tools.javac.code.*; 38import com.sun.tools.javac.code.Symbol.*; 39import com.sun.tools.javac.util.*; 40import com.sun.tools.javac.util.DefinedBy.Api; 41 42/** 43 * Utility methods for operating on types. 44 * 45 * <p><b>This is NOT part of any supported API. 46 * If you write code that depends on this, you do so at your own 47 * risk. This code and its internal interfaces are subject to change 48 * or deletion without notice.</b></p> 49 */ 50public class JavacTypes implements javax.lang.model.util.Types { 51 52 private final Symtab syms; 53 private final Types types; 54 55 public static JavacTypes instance(Context context) { 56 JavacTypes instance = context.get(JavacTypes.class); 57 if (instance == null) 58 instance = new JavacTypes(context); 59 return instance; 60 } 61 62 protected JavacTypes(Context context) { 63 context.put(JavacTypes.class, this); 64 syms = Symtab.instance(context); 65 types = Types.instance(context); 66 } 67 68 @DefinedBy(Api.LANGUAGE_MODEL) 69 public Element asElement(TypeMirror t) { 70 switch (t.getKind()) { 71 case DECLARED: 72 case INTERSECTION: 73 case ERROR: 74 case TYPEVAR: 75 Type type = cast(Type.class, t); 76 return type.asElement(); 77 default: 78 return null; 79 } 80 } 81 82 @DefinedBy(Api.LANGUAGE_MODEL) 83 public boolean isSameType(TypeMirror t1, TypeMirror t2) { 84 return types.isSameType((Type) t1, (Type) t2); 85 } 86 87 @DefinedBy(Api.LANGUAGE_MODEL) 88 public boolean isSubtype(TypeMirror t1, TypeMirror t2) { 89 validateTypeNotIn(t1, EXEC_OR_PKG); 90 validateTypeNotIn(t2, EXEC_OR_PKG); 91 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