JavacTypes.java revision 2673:bf8500822576
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 42import static com.sun.tools.javac.code.Kinds.Kind.*; 43 44/** 45 * Utility methods for operating on types. 46 * 47 * <p><b>This is NOT part of any supported API. 48 * If you write code that depends on this, you do so at your own 49 * risk. This code and its internal interfaces are subject to change 50 * or deletion without notice.</b></p> 51 */ 52public class JavacTypes implements javax.lang.model.util.Types { 53 54 private final Symtab syms; 55 private final Types types; 56 57 public static JavacTypes instance(Context context) { 58 JavacTypes instance = context.get(JavacTypes.class); 59 if (instance == null) 60 instance = new JavacTypes(context); 61 return instance; 62 } 63 64 protected JavacTypes(Context context) { 65 context.put(JavacTypes.class, this); 66 syms = Symtab.instance(context); 67 types = Types.instance(context); 68 } 69 70 @DefinedBy(Api.LANGUAGE_MODEL) 71 public Element asElement(TypeMirror t) { 72 switch (t.getKind()) { 73 case DECLARED: 74 case INTERSECTION: 75 case ERROR: 76 case TYPEVAR: 77 Type type = cast(Type.class, t); 78 return type.asElement(); 79 default: 80 return null; 81 } 82 } 83 84 @DefinedBy(Api.LANGUAGE_MODEL) 85 public boolean isSameType(TypeMirror t1, TypeMirror t2) { 86 return types.isSameType((Type) t1, (Type) t2); 87 } 88 89 @DefinedBy(Api.LANGUAGE_MODEL) 90 public boolean isSubtype(TypeMirror t1, TypeMirror t2) { 91 validateTypeNotIn(t1, EXEC_OR_PKG); 92 validateTypeNotIn(t2, EXEC_OR_PKG); 93 return types.isSubtype((Type) t1, (Type) t2); 94 } 95 96 @DefinedBy(Api.LANGUAGE_MODEL) 97 public boolean isAssignable(TypeMirror t1, TypeMirror t2) { 98 validateTypeNotIn(t1, EXEC_OR_PKG); 99 validateTypeNotIn(t2, EXEC_OR_PKG); 100 return types.isAssignable((Type) t1, (Type) t2); 101 } 102 103 @DefinedBy(Api.LANGUAGE_MODEL) 104 public boolean contains(TypeMirror t1, TypeMirror t2) { 105 validateTypeNotIn(t1, EXEC_OR_PKG); 106 validateTypeNotIn(t2, EXEC_OR_PKG); 107 return types.containsType((Type) t1, (Type) t2); 108 } 109 110 @DefinedBy(Api.LANGUAGE_MODEL) 111 public boolean isSubsignature(ExecutableType m1, ExecutableType m2) { 112 return types.isSubSignature((Type) m1, (Type) m2); 113 } 114 115 @DefinedBy(Api.LANGUAGE_MODEL) 116 public List<Type> directSupertypes(TypeMirror t) { 117 validateTypeNotIn(t, EXEC_OR_PKG); 118 return types.directSupertypes((Type) t); 119 } 120 121 @DefinedBy(Api.LANGUAGE_MODEL) 122 public TypeMirror erasure(TypeMirror t) { 123 if (t.getKind() == TypeKind.PACKAGE) 124 throw new IllegalArgumentException(t.toString()); 125 return types.erasure((Type) t); 126 } 127 128 @DefinedBy(Api.LANGUAGE_MODEL) 129 public TypeElement boxedClass(PrimitiveType p) { 130 return types.boxedClass((Type) p); 131 } 132 133 @DefinedBy(Api.LANGUAGE_MODEL) 134 public PrimitiveType unboxedType(TypeMirror t) { 135 if (t.getKind() != TypeKind.DECLARED) 136 throw new IllegalArgumentException(t.toString()); 137 Type unboxed = types.unboxedType((Type) t); 138 if (! unboxed.isPrimitive()) // only true primitives, not void 139 throw new IllegalArgumentException(t.toString()); 140 return (PrimitiveType)unboxed; 141 } 142 143 @DefinedBy(Api.LANGUAGE_MODEL) 144 public TypeMirror capture(TypeMirror t) { 145 validateTypeNotIn(t, EXEC_OR_PKG); 146 return types.capture((Type) t); 147 } 148 149 @DefinedBy(Api.LANGUAGE_MODEL) 150 public PrimitiveType getPrimitiveType(TypeKind kind) { 151 switch (kind) { 152 case BOOLEAN: return syms.booleanType; 153 case BYTE: return syms.byteType; 154 case SHORT: return syms.shortType; 155 case INT: return syms.intType; 156 case LONG: return syms.longType; 157 case CHAR: return syms.charType; 158 case FLOAT: return syms.floatType; 159 case DOUBLE: return syms.doubleType; 160 default: 161 throw new IllegalArgumentException("Not a primitive type: " + kind); 162 } 163 } 164 165 @DefinedBy(Api.LANGUAGE_MODEL) 166 public NullType getNullType() { 167 return (NullType) syms.botType; 168 } 169 170 @DefinedBy(Api.LANGUAGE_MODEL) 171 public NoType getNoType(TypeKind kind) { 172 switch (kind) { 173 case VOID: return syms.voidType; 174 case NONE: return Type.noType; 175 default: 176 throw new IllegalArgumentException(kind.toString()); 177 } 178 } 179 180 @DefinedBy(Api.LANGUAGE_MODEL) 181 public ArrayType getArrayType(TypeMirror componentType) { 182 switch (componentType.getKind()) { 183 case VOID: 184 case EXECUTABLE: 185 case WILDCARD: // heh! 186 case PACKAGE: 187 throw new IllegalArgumentException(componentType.toString()); 188 } 189 return new Type.ArrayType((Type) componentType, syms.arrayClass); 190 } 191 192 @DefinedBy(Api.LANGUAGE_MODEL) 193 public WildcardType getWildcardType(TypeMirror extendsBound, 194 TypeMirror superBound) { 195 BoundKind bkind; 196 Type bound; 197 if (extendsBound == null && superBound == null) { 198 bkind = BoundKind.UNBOUND; 199 bound = syms.objectType; 200 } else if (superBound == null) { 201 bkind = BoundKind.EXTENDS; 202 bound = (Type) extendsBound; 203 } else if (extendsBound == null) { 204 bkind = BoundKind.SUPER; 205 bound = (Type) superBound; 206 } else { 207 throw new IllegalArgumentException( 208 "Extends and super bounds cannot both be provided"); 209 } 210 switch (bound.getKind()) { 211 case ARRAY: 212 case DECLARED: 213 case ERROR: 214 case TYPEVAR: 215 return new Type.WildcardType(bound, bkind, syms.boundClass); 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 } 269 270 /** 271 * Returns the type of an element when that element is viewed as 272 * a member of, or otherwise directly contained by, a given type. 273 * For example, 274 * when viewed as a member of the parameterized type {@code Set<String>}, 275 * the {@code Set.add} method is an {@code ExecutableType} 276 * whose parameter is of type {@code String}. 277 * 278 * @param containing the containing type 279 * @param element the element 280 * @return the type of the element as viewed from the containing type 281 * @throws IllegalArgumentException if the element is not a valid one 282 * for the given type 283 */ 284 @DefinedBy(Api.LANGUAGE_MODEL) 285 public TypeMirror asMemberOf(DeclaredType containing, Element element) { 286 Type site = (Type)containing; 287 Symbol sym = (Symbol)element; 288 if (types.asSuper(site, sym.getEnclosingElement()) == null) 289 throw new IllegalArgumentException(sym + "@" + site); 290 return types.memberType(site, sym); 291 } 292 293 294 private static final Set<TypeKind> EXEC_OR_PKG = 295 EnumSet.of(TypeKind.EXECUTABLE, TypeKind.PACKAGE); 296 297 /** 298 * Throws an IllegalArgumentException if a type's kind is one of a set. 299 */ 300 private void validateTypeNotIn(TypeMirror t, Set<TypeKind> invalidKinds) { 301 if (invalidKinds.contains(t.getKind())) 302 throw new IllegalArgumentException(t.toString()); 303 } 304 305 /** 306 * Returns an object cast to the specified type. 307 * @throws NullPointerException if the object is {@code null} 308 * @throws IllegalArgumentException if the object is of the wrong type 309 */ 310 private static <T> T cast(Class<T> clazz, Object o) { 311 if (! clazz.isInstance(o)) 312 throw new IllegalArgumentException(o.toString()); 313 return clazz.cast(o); 314 } 315 316 public Set<MethodSymbol> getOverriddenMethods(Element elem) { 317 if (elem.getKind() != ElementKind.METHOD 318 || elem.getModifiers().contains(Modifier.STATIC) 319 || elem.getModifiers().contains(Modifier.PRIVATE)) 320 return Collections.emptySet(); 321 322 if (!(elem instanceof MethodSymbol)) 323 throw new IllegalArgumentException(); 324 325 MethodSymbol m = (MethodSymbol) elem; 326 ClassSymbol origin = (ClassSymbol) m.owner; 327 328 Set<MethodSymbol> results = new LinkedHashSet<>(); 329 for (Type t : types.closure(origin.type)) { 330 if (t != origin.type) { 331 ClassSymbol c = (ClassSymbol) t.tsym; 332 for (Symbol sym : c.members().getSymbolsByName(m.name)) { 333 if (sym.kind == MTH && m.overrides(sym, origin, types, true)) { 334 results.add((MethodSymbol) sym); 335 } 336 } 337 } 338 } 339 340 return results; 341 } 342} 343