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