1 /* 2 * Copyright (c) 2005, 2013, 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 com.sun.tools.javac.model; 27 28 import java.util.Collections; 29 import java.util.EnumSet; 30 import java.util.LinkedHashSet; 31 import java.util.List; 32 import java.util.Set; 33 34 import javax.lang.model.element.*; 35 import javax.lang.model.type.*; 36 37 import com.sun.tools.javac.code.*; 38 import com.sun.tools.javac.code.Symbol.*; 39 import com.sun.tools.javac.util.*; 40 41 /** 42 * Utility methods for operating on types. 43 * 44 * <p><b>This is NOT part of any supported API. 45 * If you write code that depends on this, you do so at your own 46 * risk. This code and its internal interfaces are subject to change 47 * or deletion without notice.</b></p> 48 */ 49 public class JavacTypes implements javax.lang.model.util.Types { 50 51 private Symtab syms; 52 private Types types; 53 instance(Context context)54 public static JavacTypes instance(Context context) { 55 JavacTypes instance = context.get(JavacTypes.class); 56 if (instance == null) 57 instance = new JavacTypes(context); 58 return instance; 59 } 60 61 /** 62 * Public for use only by JavacProcessingEnvironment 63 */ JavacTypes(Context context)64 protected JavacTypes(Context context) { 65 setContext(context); 66 } 67 68 /** 69 * Use a new context. May be called from outside to update 70 * internal state for a new annotation-processing round. 71 */ setContext(Context context)72 public void setContext(Context context) { 73 context.put(JavacTypes.class, this); 74 syms = Symtab.instance(context); 75 types = Types.instance(context); 76 } 77 asElement(TypeMirror t)78 public Element asElement(TypeMirror t) { 79 switch (t.getKind()) { 80 case DECLARED: 81 case INTERSECTION: 82 case ERROR: 83 case TYPEVAR: 84 Type type = cast(Type.class, t); 85 return type.asElement(); 86 default: 87 return null; 88 } 89 } 90 isSameType(TypeMirror t1, TypeMirror t2)91 public boolean isSameType(TypeMirror t1, TypeMirror t2) { 92 return types.isSameType((Type) t1, (Type) t2); 93 } 94 isSubtype(TypeMirror t1, TypeMirror t2)95 public boolean isSubtype(TypeMirror t1, TypeMirror t2) { 96 validateTypeNotIn(t1, EXEC_OR_PKG); 97 validateTypeNotIn(t2, EXEC_OR_PKG); 98 return types.isSubtype((Type) t1, (Type) t2); 99 } 100 isAssignable(TypeMirror t1, TypeMirror t2)101 public boolean isAssignable(TypeMirror t1, TypeMirror t2) { 102 validateTypeNotIn(t1, EXEC_OR_PKG); 103 validateTypeNotIn(t2, EXEC_OR_PKG); 104 return types.isAssignable((Type) t1, (Type) t2); 105 } 106 contains(TypeMirror t1, TypeMirror t2)107 public boolean contains(TypeMirror t1, TypeMirror t2) { 108 validateTypeNotIn(t1, EXEC_OR_PKG); 109 validateTypeNotIn(t2, EXEC_OR_PKG); 110 return types.containsType((Type) t1, (Type) t2); 111 } 112 isSubsignature(ExecutableType m1, ExecutableType m2)113 public boolean isSubsignature(ExecutableType m1, ExecutableType m2) { 114 return types.isSubSignature((Type) m1, (Type) m2); 115 } 116 directSupertypes(TypeMirror t)117 public List<Type> directSupertypes(TypeMirror t) { 118 validateTypeNotIn(t, EXEC_OR_PKG); 119 return types.directSupertypes((Type) t); 120 } 121 erasure(TypeMirror t)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 boxedClass(PrimitiveType p)128 public TypeElement boxedClass(PrimitiveType p) { 129 return types.boxedClass((Type) p); 130 } 131 unboxedType(TypeMirror t)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 capture(TypeMirror t)141 public TypeMirror capture(TypeMirror t) { 142 validateTypeNotIn(t, EXEC_OR_PKG); 143 return types.capture((Type) t); 144 } 145 getPrimitiveType(TypeKind kind)146 public PrimitiveType getPrimitiveType(TypeKind kind) { 147 switch (kind) { 148 case BOOLEAN: return syms.booleanType; 149 case BYTE: return syms.byteType; 150 case SHORT: return syms.shortType; 151 case INT: return syms.intType; 152 case LONG: return syms.longType; 153 case CHAR: return syms.charType; 154 case FLOAT: return syms.floatType; 155 case DOUBLE: return syms.doubleType; 156 default: 157 throw new IllegalArgumentException("Not a primitive type: " + kind); 158 } 159 } 160 getNullType()161 public NullType getNullType() { 162 return (NullType) syms.botType; 163 } 164 getNoType(TypeKind kind)165 public NoType getNoType(TypeKind kind) { 166 switch (kind) { 167 case VOID: return syms.voidType; 168 case NONE: return Type.noType; 169 default: 170 throw new IllegalArgumentException(kind.toString()); 171 } 172 } 173 getArrayType(TypeMirror componentType)174 public ArrayType getArrayType(TypeMirror componentType) { 175 switch (componentType.getKind()) { 176 case VOID: 177 case EXECUTABLE: 178 case WILDCARD: // heh! 179 case PACKAGE: 180 throw new IllegalArgumentException(componentType.toString()); 181 } 182 return new Type.ArrayType((Type) componentType, syms.arrayClass); 183 } 184 getWildcardType(TypeMirror extendsBound, TypeMirror superBound)185 public WildcardType getWildcardType(TypeMirror extendsBound, 186 TypeMirror superBound) { 187 BoundKind bkind; 188 Type bound; 189 if (extendsBound == null && superBound == null) { 190 bkind = BoundKind.UNBOUND; 191 bound = syms.objectType; 192 } else if (superBound == null) { 193 bkind = BoundKind.EXTENDS; 194 bound = (Type) extendsBound; 195 } else if (extendsBound == null) { 196 bkind = BoundKind.SUPER; 197 bound = (Type) superBound; 198 } else { 199 throw new IllegalArgumentException( 200 "Extends and super bounds cannot both be provided"); 201 } 202 switch (bound.getKind()) { 203 case ARRAY: 204 case DECLARED: 205 case ERROR: 206 case TYPEVAR: 207 return new Type.WildcardType(bound, bkind, syms.boundClass); 208 default: 209 throw new IllegalArgumentException(bound.toString()); 210 } 211 } 212 getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs)213 public DeclaredType getDeclaredType(TypeElement typeElem, 214 TypeMirror... typeArgs) { 215 ClassSymbol sym = (ClassSymbol) typeElem; 216 217 if (typeArgs.length == 0) 218 return (DeclaredType) sym.erasure(types); 219 if (sym.type.getEnclosingType().isParameterized()) 220 throw new IllegalArgumentException(sym.toString()); 221 222 return getDeclaredType0(sym.type.getEnclosingType(), sym, typeArgs); 223 } 224 getDeclaredType(DeclaredType enclosing, TypeElement typeElem, TypeMirror... typeArgs)225 public DeclaredType getDeclaredType(DeclaredType enclosing, 226 TypeElement typeElem, 227 TypeMirror... typeArgs) { 228 if (enclosing == null) 229 return getDeclaredType(typeElem, typeArgs); 230 231 ClassSymbol sym = (ClassSymbol) typeElem; 232 Type outer = (Type) enclosing; 233 234 if (outer.tsym != sym.owner.enclClass()) 235 throw new IllegalArgumentException(enclosing.toString()); 236 if (!outer.isParameterized()) 237 return getDeclaredType(typeElem, typeArgs); 238 239 return getDeclaredType0(outer, sym, typeArgs); 240 } 241 // where getDeclaredType0(Type outer, ClassSymbol sym, TypeMirror... typeArgs)242 private DeclaredType getDeclaredType0(Type outer, 243 ClassSymbol sym, 244 TypeMirror... typeArgs) { 245 if (typeArgs.length != sym.type.getTypeArguments().length()) 246 throw new IllegalArgumentException( 247 "Incorrect number of type arguments"); 248 249 ListBuffer<Type> targs = new ListBuffer<Type>(); 250 for (TypeMirror t : typeArgs) { 251 if (!(t instanceof ReferenceType || t instanceof WildcardType)) 252 throw new IllegalArgumentException(t.toString()); 253 targs.append((Type) t); 254 } 255 // TODO: Would like a way to check that type args match formals. 256 257 return (DeclaredType) new Type.ClassType(outer, targs.toList(), sym); 258 } 259 260 /** 261 * Returns the type of an element when that element is viewed as 262 * a member of, or otherwise directly contained by, a given type. 263 * For example, 264 * when viewed as a member of the parameterized type {@code Set<String>}, 265 * the {@code Set.add} method is an {@code ExecutableType} 266 * whose parameter is of type {@code String}. 267 * 268 * @param containing the containing type 269 * @param element the element 270 * @return the type of the element as viewed from the containing type 271 * @throws IllegalArgumentException if the element is not a valid one 272 * for the given type 273 */ asMemberOf(DeclaredType containing, Element element)274 public TypeMirror asMemberOf(DeclaredType containing, Element element) { 275 Type site = (Type)containing; 276 Symbol sym = (Symbol)element; 277 if (types.asSuper(site, sym.getEnclosingElement()) == null) 278 throw new IllegalArgumentException(sym + "@" + site); 279 return types.memberType(site, sym); 280 } 281 282 283 private static final Set<TypeKind> EXEC_OR_PKG = 284 EnumSet.of(TypeKind.EXECUTABLE, TypeKind.PACKAGE); 285 286 /** 287 * Throws an IllegalArgumentException if a type's kind is one of a set. 288 */ validateTypeNotIn(TypeMirror t, Set<TypeKind> invalidKinds)289 private void validateTypeNotIn(TypeMirror t, Set<TypeKind> invalidKinds) { 290 if (invalidKinds.contains(t.getKind())) 291 throw new IllegalArgumentException(t.toString()); 292 } 293 294 /** 295 * Returns an object cast to the specified type. 296 * @throws NullPointerException if the object is {@code null} 297 * @throws IllegalArgumentException if the object is of the wrong type 298 */ cast(Class<T> clazz, Object o)299 private static <T> T cast(Class<T> clazz, Object o) { 300 if (! clazz.isInstance(o)) 301 throw new IllegalArgumentException(o.toString()); 302 return clazz.cast(o); 303 } 304 getOverriddenMethods(Element elem)305 public Set<MethodSymbol> getOverriddenMethods(Element elem) { 306 if (elem.getKind() != ElementKind.METHOD 307 || elem.getModifiers().contains(Modifier.STATIC) 308 || elem.getModifiers().contains(Modifier.PRIVATE)) 309 return Collections.emptySet(); 310 311 if (!(elem instanceof MethodSymbol)) 312 throw new IllegalArgumentException(); 313 314 MethodSymbol m = (MethodSymbol) elem; 315 ClassSymbol origin = (ClassSymbol) m.owner; 316 317 Set<MethodSymbol> results = new LinkedHashSet<MethodSymbol>(); 318 for (Type t : types.closure(origin.type)) { 319 if (t != origin.type) { 320 ClassSymbol c = (ClassSymbol) t.tsym; 321 for (Scope.Entry e = c.members().lookup(m.name); e.scope != null; e = e.next()) { 322 if (e.sym.kind == Kinds.MTH && m.overrides(e.sym, origin, types, true)) { 323 results.add((MethodSymbol) e.sym); 324 } 325 } 326 } 327 } 328 329 return results; 330 } 331 } 332