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); 97 validateTypeNotIn(t2, EXEC_OR_PKG); 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); 104 validateTypeNotIn(t2, EXEC_OR_PKG); 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); 111 validateTypeNotIn(t2, EXEC_OR_PKG); 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); 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 if (t.getKind() == TypeKind.PACKAGE) 132 throw new IllegalArgumentException(t.toString()); 133 return types.erasure((Type)t).stripMetadataIfNeeded(); 134 } 135 136 @DefinedBy(Api.LANGUAGE_MODEL) 137 public TypeElement boxedClass(PrimitiveType p) { 138 return types.boxedClass((Type) p); 139 } 140 141 @DefinedBy(Api.LANGUAGE_MODEL) 142 public PrimitiveType unboxedType(TypeMirror t) { 143 if (t.getKind() != TypeKind.DECLARED) 144 throw new IllegalArgumentException(t.toString()); 145 Type unboxed = types.unboxedType((Type) t); 146 if (! unboxed.isPrimitive()) // only true primitives, not void 147 throw new IllegalArgumentException(t.toString()); 148 return (PrimitiveType)unboxed; 149 } 150 151 @DefinedBy(Api.LANGUAGE_MODEL) 152 public TypeMirror capture(TypeMirror t) { 153 validateTypeNotIn(t, EXEC_OR_PKG); 154 return types.capture((Type)t).stripMetadataIfNeeded(); 155 } 156 157 @DefinedBy(Api.LANGUAGE_MODEL) 158 public PrimitiveType getPrimitiveType(TypeKind kind) { 159 switch (kind) { 160 case BOOLEAN: return syms.booleanType; 161 case BYTE: return syms.byteType; 162 case SHORT: return syms.shortType; 163 case INT: return syms.intType; 164 case LONG: return syms.longType; 165 case CHAR: return syms.charType; 166 case FLOAT: return syms.floatType; 167 case DOUBLE: return syms.doubleType; 168 default: 169 throw new IllegalArgumentException("Not a primitive type: " + kind); 170 } 171 } 172 173 @DefinedBy(Api.LANGUAGE_MODEL) 174 public NullType getNullType() { 175 return (NullType) syms.botType; 176 } 177 178 @DefinedBy(Api.LANGUAGE_MODEL) 179 public NoType getNoType(TypeKind kind) { 180 switch (kind) { 181 case VOID: return syms.voidType; 182 case NONE: return Type.noType; 183 default: 184 throw new IllegalArgumentException(kind.toString()); 185 } 186 } 187 188 @DefinedBy(Api.LANGUAGE_MODEL) 189 public ArrayType getArrayType(TypeMirror componentType) { 190 switch (componentType.getKind()) { 191 case VOID: 192 case EXECUTABLE: 193 case WILDCARD: // heh! 194 case PACKAGE: 195 throw new IllegalArgumentException(componentType.toString()); 196 } 197 return new Type.ArrayType((Type) componentType, syms.arrayClass); 198 } 199 200 @DefinedBy(Api.LANGUAGE_MODEL) 201 public WildcardType getWildcardType(TypeMirror extendsBound, 202 TypeMirror superBound) { 203 BoundKind bkind; 204 Type bound; 205 if (extendsBound == null && superBound == null) { 206 bkind = BoundKind.UNBOUND; 207 bound = syms.objectType; 208 } else if (superBound == null) { 209 bkind = BoundKind.EXTENDS; 210 bound = (Type) extendsBound; 211 } else if (extendsBound == null) { 212 bkind = BoundKind.SUPER; 213 bound = (Type) superBound; 214 } else { 215 throw new IllegalArgumentException( 216 "Extends and super bounds cannot both be provided"); 217 } 218 switch (bound.getKind()) { 219 case ARRAY: 220 case DECLARED: 221 case ERROR: 222 case TYPEVAR: 223 return new Type.WildcardType(bound, bkind, syms.boundClass); 224 default: 225 throw new IllegalArgumentException(bound.toString()); 226 } 227 } 228 229 @DefinedBy(Api.LANGUAGE_MODEL) 230 public DeclaredType getDeclaredType(TypeElement typeElem, 231 TypeMirror... typeArgs) { 232 ClassSymbol sym = (ClassSymbol) typeElem; 233 234 if (typeArgs.length == 0) 235 return (DeclaredType) sym.erasure(types); 236 if (sym.type.getEnclosingType().isParameterized()) 237 throw new IllegalArgumentException(sym.toString()); 238 239 return getDeclaredType0(sym.type.getEnclosingType(), sym, typeArgs); 240 } 241 242 @DefinedBy(Api.LANGUAGE_MODEL) 243 public DeclaredType getDeclaredType(DeclaredType enclosing, 244 TypeElement typeElem, 245 TypeMirror... typeArgs) { 246 if (enclosing == null) 247 return getDeclaredType(typeElem, typeArgs); 248 249 ClassSymbol sym = (ClassSymbol) typeElem; 250 Type outer = (Type) enclosing; 251 252 if (outer.tsym != sym.owner.enclClass()) 253 throw new IllegalArgumentException(enclosing.toString()); 254 if (!outer.isParameterized()) 255 return getDeclaredType(typeElem, typeArgs); 256 257 return getDeclaredType0(outer, sym, typeArgs); 258 } 259 // where 260 private DeclaredType getDeclaredType0(Type outer, 261 ClassSymbol sym, 262 TypeMirror... typeArgs) { 263 if (typeArgs.length != sym.type.getTypeArguments().length()) 264 throw new IllegalArgumentException( 265 "Incorrect number of type arguments"); 266 267 ListBuffer<Type> targs = new ListBuffer<>(); 268 for (TypeMirror t : typeArgs) { 269 if (!(t instanceof ReferenceType || t instanceof WildcardType)) 270 throw new IllegalArgumentException(t.toString()); 271 targs.append((Type) t); 272 } 273 // TODO: Would like a way to check that type args match formals. 274 275 return (DeclaredType) new Type.ClassType(outer, targs.toList(), sym); 276 } 277 278 /** 279 * Returns the type of an element when that element is viewed as 280 * a member of, or otherwise directly contained by, a given type. 281 * For example, 282 * when viewed as a member of the parameterized type {@code Set<String>}, 283 * the {@code Set.add} method is an {@code ExecutableType} 284 * whose parameter is of type {@code String}. 285 * 286 * @param containing the containing type 287 * @param element the element 288 * @return the type of the element as viewed from the containing type 289 * @throws IllegalArgumentException if the element is not a valid one 290 * for the given type 291 */ 292 @DefinedBy(Api.LANGUAGE_MODEL) 293 public TypeMirror asMemberOf(DeclaredType containing, Element element) { 294 Type site = (Type)containing; 295 Symbol sym = (Symbol)element; 296 if (types.asSuper(site, sym.getEnclosingElement()) == null) 297 throw new IllegalArgumentException(sym + "@" + site); 298 return types.memberType(site, sym); 299 } 300 301 302 private static final Set<TypeKind> EXEC_OR_PKG = 303 EnumSet.of(TypeKind.EXECUTABLE, TypeKind.PACKAGE); 304 305 /** 306 * Throws an IllegalArgumentException if a type's kind is one of a set. 307 */ 308 private void validateTypeNotIn(TypeMirror t, Set<TypeKind> invalidKinds) { 309 if (invalidKinds.contains(t.getKind())) 310 throw new IllegalArgumentException(t.toString()); 311 } 312 313 /** 314 * Returns an object cast to the specified type. 315 * @throws NullPointerException if the object is {@code null} 316 * @throws IllegalArgumentException if the object is of the wrong type 317 */ 318 private static <T> T cast(Class<T> clazz, Object o) { 319 if (! clazz.isInstance(o)) 320 throw new IllegalArgumentException(o.toString()); 321 return clazz.cast(o); 322 } 323 324 public Set<MethodSymbol> getOverriddenMethods(Element elem) { 325 if (elem.getKind() != ElementKind.METHOD 326 || elem.getModifiers().contains(Modifier.STATIC) 327 || elem.getModifiers().contains(Modifier.PRIVATE)) 328 return Collections.emptySet(); 329 330 if (!(elem instanceof MethodSymbol)) 331 throw new IllegalArgumentException(); 332 333 MethodSymbol m = (MethodSymbol) elem; 334 ClassSymbol origin = (ClassSymbol) m.owner; 335 336 Set<MethodSymbol> results = new LinkedHashSet<>(); 337 for (Type t : types.closure(origin.type)) { 338 if (t != origin.type) { 339 ClassSymbol c = (ClassSymbol) t.tsym; 340 for (Symbol sym : c.members().getSymbolsByName(m.name)) { 341 if (sym.kind == MTH && m.overrides(sym, origin, types, true)) { 342 results.add((MethodSymbol) sym); 343 } 344 } 345 } 346 } 347 348 return results; 349 } 350 }