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