duke@1: /* jjg@1521: * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@1: * duke@1: * This code is free software; you can redistribute it and/or modify it duke@1: * under the terms of the GNU General Public License version 2 only, as ohair@554: * published by the Free Software Foundation. Oracle designates this duke@1: * particular file as subject to the "Classpath" exception as provided ohair@554: * by Oracle in the LICENSE file that accompanied this code. duke@1: * duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@1: * version 2 for more details (a copy is included in the LICENSE file that duke@1: * accompanied this code). duke@1: * duke@1: * You should have received a copy of the GNU General Public License version duke@1: * 2 along with this work; if not, write to the Free Software Foundation, duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@1: * ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@554: * or visit www.oracle.com if you need additional information or have any ohair@554: * questions. duke@1: */ duke@1: duke@1: package com.sun.tools.javac.model; duke@1: jjg@1521: import java.lang.annotation.Annotation; jjg@1455: import java.util.Collections; jjg@1455: import java.util.EnumSet; jjg@1455: import java.util.LinkedHashSet; duke@1: import java.util.List; duke@1: import java.util.Set; jjg@1455: duke@1: import javax.lang.model.element.*; duke@1: import javax.lang.model.type.*; jjg@1455: duke@1: import com.sun.tools.javac.code.*; duke@1: import com.sun.tools.javac.code.Symbol.*; duke@1: import com.sun.tools.javac.util.*; duke@1: duke@1: /** duke@1: * Utility methods for operating on types. duke@1: * jjg@581: *

This is NOT part of any supported API. duke@1: * If you write code that depends on this, you do so at your own duke@1: * risk. This code and its internal interfaces are subject to change duke@1: * or deletion without notice.

duke@1: */ duke@1: public class JavacTypes implements javax.lang.model.util.Types { duke@1: duke@1: private Symtab syms; duke@1: private Types types; duke@1: duke@1: public static JavacTypes instance(Context context) { jjg@706: JavacTypes instance = context.get(JavacTypes.class); jjg@706: if (instance == null) duke@1: instance = new JavacTypes(context); duke@1: return instance; duke@1: } duke@1: duke@1: /** duke@1: * Public for use only by JavacProcessingEnvironment duke@1: */ jjg@706: protected JavacTypes(Context context) { duke@1: setContext(context); duke@1: } duke@1: duke@1: /** duke@1: * Use a new context. May be called from outside to update duke@1: * internal state for a new annotation-processing round. duke@1: */ duke@1: public void setContext(Context context) { jjg@706: context.put(JavacTypes.class, this); duke@1: syms = Symtab.instance(context); duke@1: types = Types.instance(context); duke@1: } duke@1: duke@1: public Element asElement(TypeMirror t) { jjg@988: switch (t.getKind()) { jjg@988: case DECLARED: mcimadamore@1436: case INTERSECTION: jjg@988: case ERROR: jjg@988: case TYPEVAR: jjg@988: Type type = cast(Type.class, t); jjg@928: return type.asElement(); jjg@928: default: jjg@928: return null; jjg@928: } duke@1: } duke@1: duke@1: public boolean isSameType(TypeMirror t1, TypeMirror t2) { duke@1: return types.isSameType((Type) t1, (Type) t2); duke@1: } duke@1: duke@1: public boolean isSubtype(TypeMirror t1, TypeMirror t2) { duke@1: validateTypeNotIn(t1, EXEC_OR_PKG); duke@1: validateTypeNotIn(t2, EXEC_OR_PKG); duke@1: return types.isSubtype((Type) t1, (Type) t2); duke@1: } duke@1: duke@1: public boolean isAssignable(TypeMirror t1, TypeMirror t2) { duke@1: validateTypeNotIn(t1, EXEC_OR_PKG); duke@1: validateTypeNotIn(t2, EXEC_OR_PKG); duke@1: return types.isAssignable((Type) t1, (Type) t2); duke@1: } duke@1: duke@1: public boolean contains(TypeMirror t1, TypeMirror t2) { duke@1: validateTypeNotIn(t1, EXEC_OR_PKG); duke@1: validateTypeNotIn(t2, EXEC_OR_PKG); mcimadamore@675: return types.containsType((Type) t1, (Type) t2); duke@1: } duke@1: duke@1: public boolean isSubsignature(ExecutableType m1, ExecutableType m2) { duke@1: return types.isSubSignature((Type) m1, (Type) m2); duke@1: } duke@1: duke@1: public List directSupertypes(TypeMirror t) { duke@1: validateTypeNotIn(t, EXEC_OR_PKG); duke@1: Type type = (Type) t; duke@1: Type sup = types.supertype(type); duke@1: return (sup == Type.noType || sup == type || sup == null) duke@1: ? types.interfaces(type) duke@1: : types.interfaces(type).prepend(sup); duke@1: } duke@1: duke@1: public TypeMirror erasure(TypeMirror t) { duke@1: if (t.getKind() == TypeKind.PACKAGE) duke@1: throw new IllegalArgumentException(t.toString()); duke@1: return types.erasure((Type) t); duke@1: } duke@1: duke@1: public TypeElement boxedClass(PrimitiveType p) { duke@1: return types.boxedClass((Type) p); duke@1: } duke@1: duke@1: public PrimitiveType unboxedType(TypeMirror t) { duke@1: if (t.getKind() != TypeKind.DECLARED) duke@1: throw new IllegalArgumentException(t.toString()); duke@1: Type unboxed = types.unboxedType((Type) t); duke@1: if (! unboxed.isPrimitive()) // only true primitives, not void duke@1: throw new IllegalArgumentException(t.toString()); duke@1: return unboxed; duke@1: } duke@1: duke@1: public TypeMirror capture(TypeMirror t) { duke@1: validateTypeNotIn(t, EXEC_OR_PKG); duke@1: return types.capture((Type) t); duke@1: } duke@1: duke@1: public PrimitiveType getPrimitiveType(TypeKind kind) { duke@1: switch (kind) { duke@1: case BOOLEAN: return syms.booleanType; duke@1: case BYTE: return syms.byteType; duke@1: case SHORT: return syms.shortType; duke@1: case INT: return syms.intType; duke@1: case LONG: return syms.longType; duke@1: case CHAR: return syms.charType; duke@1: case FLOAT: return syms.floatType; duke@1: case DOUBLE: return syms.doubleType; duke@1: default: duke@1: throw new IllegalArgumentException("Not a primitive type: " + kind); duke@1: } duke@1: } duke@1: duke@1: public NullType getNullType() { duke@1: return (NullType) syms.botType; duke@1: } duke@1: duke@1: public NoType getNoType(TypeKind kind) { duke@1: switch (kind) { duke@1: case VOID: return syms.voidType; duke@1: case NONE: return Type.noType; duke@1: default: duke@1: throw new IllegalArgumentException(kind.toString()); duke@1: } duke@1: } duke@1: duke@1: public ArrayType getArrayType(TypeMirror componentType) { duke@1: switch (componentType.getKind()) { duke@1: case VOID: duke@1: case EXECUTABLE: duke@1: case WILDCARD: // heh! duke@1: case PACKAGE: duke@1: throw new IllegalArgumentException(componentType.toString()); duke@1: } duke@1: return new Type.ArrayType((Type) componentType, syms.arrayClass); duke@1: } duke@1: duke@1: public WildcardType getWildcardType(TypeMirror extendsBound, duke@1: TypeMirror superBound) { duke@1: BoundKind bkind; duke@1: Type bound; duke@1: if (extendsBound == null && superBound == null) { duke@1: bkind = BoundKind.UNBOUND; duke@1: bound = syms.objectType; duke@1: } else if (superBound == null) { duke@1: bkind = BoundKind.EXTENDS; duke@1: bound = (Type) extendsBound; duke@1: } else if (extendsBound == null) { duke@1: bkind = BoundKind.SUPER; duke@1: bound = (Type) superBound; duke@1: } else { duke@1: throw new IllegalArgumentException( duke@1: "Extends and super bounds cannot both be provided"); duke@1: } duke@1: switch (bound.getKind()) { duke@1: case ARRAY: duke@1: case DECLARED: duke@1: case ERROR: duke@1: case TYPEVAR: duke@1: return new Type.WildcardType(bound, bkind, syms.boundClass); duke@1: default: duke@1: throw new IllegalArgumentException(bound.toString()); duke@1: } duke@1: } duke@1: duke@1: public DeclaredType getDeclaredType(TypeElement typeElem, duke@1: TypeMirror... typeArgs) { duke@1: ClassSymbol sym = (ClassSymbol) typeElem; duke@1: duke@1: if (typeArgs.length == 0) duke@1: return (DeclaredType) sym.erasure(types); duke@1: if (sym.type.getEnclosingType().isParameterized()) duke@1: throw new IllegalArgumentException(sym.toString()); duke@1: duke@1: return getDeclaredType0(sym.type.getEnclosingType(), sym, typeArgs); duke@1: } duke@1: duke@1: public DeclaredType getDeclaredType(DeclaredType enclosing, duke@1: TypeElement typeElem, duke@1: TypeMirror... typeArgs) { duke@1: if (enclosing == null) duke@1: return getDeclaredType(typeElem, typeArgs); duke@1: duke@1: ClassSymbol sym = (ClassSymbol) typeElem; duke@1: Type outer = (Type) enclosing; duke@1: duke@1: if (outer.tsym != sym.owner.enclClass()) duke@1: throw new IllegalArgumentException(enclosing.toString()); duke@1: if (!outer.isParameterized()) duke@1: return getDeclaredType(typeElem, typeArgs); duke@1: duke@1: return getDeclaredType0(outer, sym, typeArgs); duke@1: } duke@1: // where duke@1: private DeclaredType getDeclaredType0(Type outer, duke@1: ClassSymbol sym, duke@1: TypeMirror... typeArgs) { duke@1: if (typeArgs.length != sym.type.getTypeArguments().length()) duke@1: throw new IllegalArgumentException( duke@1: "Incorrect number of type arguments"); duke@1: duke@1: ListBuffer targs = new ListBuffer(); duke@1: for (TypeMirror t : typeArgs) { duke@1: if (!(t instanceof ReferenceType || t instanceof WildcardType)) duke@1: throw new IllegalArgumentException(t.toString()); duke@1: targs.append((Type) t); duke@1: } duke@1: // TODO: Would like a way to check that type args match formals. duke@1: duke@1: return (DeclaredType) new Type.ClassType(outer, targs.toList(), sym); duke@1: } duke@1: duke@1: /** duke@1: * Returns the type of an element when that element is viewed as duke@1: * a member of, or otherwise directly contained by, a given type. duke@1: * For example, duke@1: * when viewed as a member of the parameterized type {@code Set}, duke@1: * the {@code Set.add} method is an {@code ExecutableType} duke@1: * whose parameter is of type {@code String}. duke@1: * duke@1: * @param containing the containing type duke@1: * @param element the element duke@1: * @return the type of the element as viewed from the containing type duke@1: * @throws IllegalArgumentException if the element is not a valid one duke@1: * for the given type duke@1: */ duke@1: public TypeMirror asMemberOf(DeclaredType containing, Element element) { duke@1: Type site = (Type)containing; duke@1: Symbol sym = (Symbol)element; duke@1: if (types.asSuper(site, sym.getEnclosingElement()) == null) duke@1: throw new IllegalArgumentException(sym + "@" + site); duke@1: return types.memberType(site, sym); duke@1: } duke@1: duke@1: duke@1: private static final Set EXEC_OR_PKG = duke@1: EnumSet.of(TypeKind.EXECUTABLE, TypeKind.PACKAGE); duke@1: duke@1: /** duke@1: * Throws an IllegalArgumentException if a type's kind is one of a set. duke@1: */ duke@1: private void validateTypeNotIn(TypeMirror t, Set invalidKinds) { duke@1: if (invalidKinds.contains(t.getKind())) duke@1: throw new IllegalArgumentException(t.toString()); duke@1: } duke@1: duke@1: /** duke@1: * Returns an object cast to the specified type. duke@1: * @throws NullPointerException if the object is {@code null} duke@1: * @throws IllegalArgumentException if the object is of the wrong type duke@1: */ duke@1: private static T cast(Class clazz, Object o) { duke@1: if (! clazz.isInstance(o)) duke@1: throw new IllegalArgumentException(o.toString()); duke@1: return clazz.cast(o); duke@1: } jjg@1455: jjg@1455: public Set getOverriddenMethods(Element elem) { jjg@1455: if (elem.getKind() != ElementKind.METHOD jjg@1455: || elem.getModifiers().contains(Modifier.STATIC) jjg@1455: || elem.getModifiers().contains(Modifier.PRIVATE)) jjg@1455: return Collections.emptySet(); jjg@1455: jjg@1455: if (!(elem instanceof MethodSymbol)) jjg@1455: throw new IllegalArgumentException(); jjg@1455: jjg@1455: MethodSymbol m = (MethodSymbol) elem; jjg@1455: ClassSymbol origin = (ClassSymbol) m.owner; jjg@1455: jjg@1455: Set results = new LinkedHashSet(); jjg@1455: for (Type t : types.closure(origin.type)) { jjg@1455: if (t != origin.type) { jjg@1455: ClassSymbol c = (ClassSymbol) t.tsym; jjg@1455: for (Scope.Entry e = c.members().lookup(m.name); e.scope != null; e = e.next()) { jjg@1455: if (e.sym.kind == Kinds.MTH && m.overrides(e.sym, origin, types, true)) { jjg@1455: results.add((MethodSymbol) e.sym); jjg@1455: } jjg@1455: } jjg@1455: } jjg@1455: } jjg@1455: jjg@1455: return results; jjg@1455: } jjg@1521: jjg@1521: public List typeAnnotationsOf(TypeMirror type) { jjg@1521: // TODO: these methods can be removed. jjg@1521: return null; // ((Type)type).typeAnnotations; jjg@1521: } jjg@1521: jjg@1521: public A typeAnnotationOf(TypeMirror type, jjg@1521: Class annotationType) { jjg@1521: // TODO: these methods can be removed. jjg@1521: return null; // JavacElements.getAnnotation(((Type)type).typeAnnotations, annotationType); jjg@1521: } jjg@1521: jjg@1521: public TypeMirror receiverTypeOf(ExecutableType type) { jjg@1521: return ((Type)type).asMethodType().recvtype; jjg@1521: } jjg@1521: jjg@1521: /* jjg@1521: public A receiverTypeAnnotationOf( jjg@1521: ExecutableType type, Class annotationType) { jjg@1521: return JavacElements.getAnnotation( jjg@1521: ((Type)type).asMethodType().receiverTypeAnnotations, jjg@1521: annotationType); jjg@1521: }*/ jjg@1521: duke@1: }